text: /* ---------------------------------------------------------------------- */
  /* Copyright (c) Microsoft Corporation. All rights reserved.              */
  /* Licensed under the MIT License                                         */
  /* ---------------------------------------------------------------------- */
  #pragma once
  
  #include "SharedLibrary_HashOneHotVectorizerFeaturizer.h"
  
  #include "Traits.h"
  #include "Featurizers/Structs.h"
  
  #include "SharedLibraryTests_Common.hpp"
  
  #if (defined _MSC_VER)
  #   pragma warning(push)
  
      // I don't know why MSVC thinks that there is unreachable
      // code in these methods during release builds.
  #   pragma warning(disable: 4702) // Unreachable code
  
  #   pragma warning(disable: 4701) // potentially uninitialized local variable '<name>' used
  #   pragma warning(disable: 4703) // potentially uninitialized local pointer variable '<name>' used
  #endif
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <int8> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_int8_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_int8_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int8_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int8_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int8_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_int8_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_int8_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int8_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_int8_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int8_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_int8_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int8_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_int8_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <int16> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_int16_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_int16_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int16_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int16_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int16_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_int16_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_int16_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int16_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_int16_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int16_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_int16_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int16_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_int16_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <int32> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_int32_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_int32_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int32_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int32_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int32_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_int32_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_int32_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int32_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_int32_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int32_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_int32_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int32_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_int32_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <int64> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_int64_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_int64_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int64_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int64_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_int64_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_int64_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_int64_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int64_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_int64_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_int64_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_int64_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_int64_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_int64_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <uint8> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_uint8_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_uint8_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint8_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint8_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint8_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_uint8_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_uint8_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint8_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_uint8_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint8_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_uint8_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint8_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_uint8_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <uint16> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_uint16_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_uint16_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint16_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint16_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint16_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_uint16_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_uint16_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint16_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_uint16_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint16_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_uint16_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint16_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_uint16_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <uint32> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_uint32_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_uint32_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint32_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint32_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint32_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_uint32_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_uint32_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint32_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_uint32_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint32_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_uint32_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint32_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_uint32_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <uint64> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_uint64_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_uint64_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint64_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint64_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_uint64_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_uint64_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_uint64_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint64_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_uint64_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_uint64_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_uint64_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_uint64_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_uint64_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <float> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_float_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_float_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_float_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_float_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_float_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_float_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_float_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_float_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_float_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_float_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_float_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_float_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_float_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <double> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_double_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_double_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_double_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_double_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_double_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_double_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_double_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_double_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_double_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_double_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_double_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_double_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_double_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <bool> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_bool_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_bool_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_bool_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_bool_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_bool_Fit(pEstimatorHandle, input, &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_bool_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_bool_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_bool_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_bool_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_bool_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_bool_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(bool input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_bool_Transform(pTransformerHandle, input, &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_bool_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  /* ---------------------------------------------------------------------- */
  /* |  HashOneHotVectorizerFeaturizer <string> */
  template <typename VectorInputT, typename... ConstructorArgTs>
  void HashOneHotVectorizerFeaturizer_string_Test(
      std::vector<VectorInputT> const &training_input,
      std::vector<VectorInputT> const &inference_input,
      std::function<bool (std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> const &)> const &verify_func,
      ConstructorArgTs &&... constructor_args
  ) {
      ErrorInfoHandle * pErrorInfo(nullptr);
  
      // Create the estimator
      HashOneHotVectorizerFeaturizer_string_EstimatorHandle *pEstimatorHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_string_CreateEstimator(std::forward<ConstructorArgTs>(constructor_args)..., &pEstimatorHandle, &pErrorInfo));
      REQUIRE(pEstimatorHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Train
      if(training_input.empty() == false) {
          typename std::vector<VectorInputT>::const_iterator iter(training_input.begin());
  
          while(true) {
              TrainingState trainingState(0);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_string_GetState(pEstimatorHandle, &trainingState, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(trainingState != Training)
                  break;
  
              FitResult result(0);
              auto const & input(*iter);
  
              REQUIRE(HashOneHotVectorizerFeaturizer_string_Fit(pEstimatorHandle, input.c_str(), &result, &pErrorInfo));
              REQUIRE(pErrorInfo == nullptr);
  
              if(result == ResetAndContinue) {
                  iter = training_input.begin();
                  continue;
              }
  
              ++iter;
              if(iter == training_input.end()) {
                  REQUIRE(HashOneHotVectorizerFeaturizer_string_OnDataCompleted(pEstimatorHandle, &pErrorInfo));
                  REQUIRE(pErrorInfo == nullptr);
  
                  iter = training_input.begin();
              }
          }
      }
  
      HashOneHotVectorizerFeaturizer_string_CompleteTraining(pEstimatorHandle, &pErrorInfo);
      REQUIRE(pErrorInfo == nullptr);
  
      // Once here, training should be complete
      {
          bool is_complete(false);
  
          REQUIRE(HashOneHotVectorizerFeaturizer_string_IsTrainingComplete(pEstimatorHandle, &is_complete, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
          REQUIRE(is_complete);
      }
  
      // Create the Transformer
      HashOneHotVectorizerFeaturizer_string_TransformerHandle * pTransformerHandle(nullptr);
  
      REQUIRE(HashOneHotVectorizerFeaturizer_string_CreateTransformerFromEstimator(pEstimatorHandle, &pTransformerHandle, &pErrorInfo));
      REQUIRE(pTransformerHandle != nullptr);
      REQUIRE(pErrorInfo == nullptr);
  
      // Destroy the estimator
      REQUIRE(HashOneHotVectorizerFeaturizer_string_DestroyEstimator(pEstimatorHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  
      // Inference
      std::vector<Microsoft::Featurizer::Featurizers::SingleValueSparseVectorEncoding<std::uint8_t>> results;
  
      results.reserve(inference_input.size());
  
      for(auto const & input : inference_input) {
          uint64_t results_numElements;
          std::uint8_t results_value;
          uint64_t results_index;
  
          REQUIRE(HashOneHotVectorizerFeaturizer_string_Transform(pTransformerHandle, input.c_str(), &results_numElements, &results_value, &results_index, &pErrorInfo));
          REQUIRE(pErrorInfo == nullptr);
  
          results.emplace_back(results_numElements, results_value, results_index);
          // No inline destroy statement
      }
  
      REQUIRE(verify_func(results));
  
      // No trailing destroy statement
  
      // Destroy the transformer
      REQUIRE(HashOneHotVectorizerFeaturizer_string_DestroyTransformer(pTransformerHandle, &pErrorInfo));
      REQUIRE(pErrorInfo == nullptr);
  }
  
  #if (defined _MSC_VER)
  #   pragma warning(pop)
  #endif
  