This is an automated email from the ASF dual-hosted git repository.

lordgamez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit fbd69e7e211b3f2fbd72d8ce806ac025aa63b6e0
Author: Ferenc Gerlits <fgerl...@gmail.com>
AuthorDate: Wed Aug 9 14:50:53 2023 +0200

    MINIFICPP-2164 Use a list of types for allowed types in PropertyDefinition
    
    Signed-off-by: Gabor Gyimesi <gamezb...@gmail.com>
    
    This closes #1626
---
 extensions/elasticsearch/PostElasticsearch.h       |  9 +-
 extensions/gcp/processors/GCSProcessor.h           |  4 +-
 extensions/http-curl/processors/InvokeHTTP.h       |  4 +-
 extensions/librdkafka/KafkaProcessorBase.h         | 52 ++++++------
 extensions/splunk/SplunkHECProcessor.h             | 40 ++++-----
 extensions/standard-processors/processors/GetTCP.h |  4 +-
 .../standard-processors/processors/ListenSyslog.h  |  4 +-
 .../standard-processors/processors/ListenTCP.h     |  4 +-
 .../standard-processors/processors/PutFile.h       |  2 +-
 extensions/standard-processors/processors/PutTCP.h | 98 +++++++++++-----------
 .../standard-processors/processors/TailFile.h      |  4 +-
 .../tests/unit/YamlConfigurationTests.cpp          |  8 +-
 libminifi/include/core/OutputAttributeDefinition.h |  4 +-
 libminifi/include/core/PropertyDefinition.h        | 18 ++--
 libminifi/include/core/PropertyDefinitionBuilder.h | 41 +++++----
 libminifi/src/core/Property.cpp                    |  6 +-
 libminifi/test/unit/ComponentManifestTests.cpp     |  4 +-
 libminifi/test/unit/TypeListTests.cpp              | 61 ++++++++++++++
 18 files changed, 217 insertions(+), 150 deletions(-)

diff --git a/extensions/elasticsearch/PostElasticsearch.h 
b/extensions/elasticsearch/PostElasticsearch.h
index 367e35d21..ec213b982 100644
--- a/extensions/elasticsearch/PostElasticsearch.h
+++ b/extensions/elasticsearch/PostElasticsearch.h
@@ -53,16 +53,16 @@ class PostElasticsearch : public core::Processor {
       .withPropertyType(core::StandardPropertyTypes::UNSIGNED_LONG_TYPE)
       .withDefaultValue("100")
       .build();
-  EXTENSIONAPI static constexpr auto ElasticCredentials = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("Elasticsearch 
Credentials Provider Service")
+  EXTENSIONAPI static constexpr auto ElasticCredentials = 
core::PropertyDefinitionBuilder<>::createProperty("Elasticsearch Credentials 
Provider Service")
       .withDescription("The Controller Service used to obtain Elasticsearch 
credentials.")
       .isRequired(true)
-      
.withAllowedTypes({core::className<ElasticsearchCredentialsControllerService>()})
+      .withAllowedTypes<ElasticsearchCredentialsControllerService>()
       .build();
-  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
+  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The SSL Context Service used to provide client 
certificate "
           "information for TLS/SSL (https) connections.")
       .isRequired(false)
-      
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
       .build();
   EXTENSIONAPI static constexpr auto Hosts = 
core::PropertyDefinitionBuilder<>::createProperty("Hosts")
       .withDescription("A comma-separated list of HTTP hosts that host 
Elasticsearch query nodes. Currently only supports a single host.")
@@ -90,7 +90,6 @@ class PostElasticsearch : public core::Processor {
       Identifier
   };
 
-
   EXTENSIONAPI static constexpr auto Success = 
core::RelationshipDefinition{"success", "All flowfiles that succeed in being 
transferred into Elasticsearch go here."};
   EXTENSIONAPI static constexpr auto Failure = 
core::RelationshipDefinition{"failure", "All flowfiles that fail for reasons 
unrelated to server availability go to this relationship."};
   EXTENSIONAPI static constexpr auto Error = 
core::RelationshipDefinition{"error", "All flowfiles that Elasticsearch 
responded to with an error go to this relationship."};
diff --git a/extensions/gcp/processors/GCSProcessor.h 
b/extensions/gcp/processors/GCSProcessor.h
index b54fbe691..8cfbe9c1d 100644
--- a/extensions/gcp/processors/GCSProcessor.h
+++ b/extensions/gcp/processors/GCSProcessor.h
@@ -39,10 +39,10 @@ class GCSProcessor : public core::Processor {
    logger_(std::move(logger)) {
   }
 
-  EXTENSIONAPI static constexpr auto GCPCredentials = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("GCP Credentials Provider 
Service")
+  EXTENSIONAPI static constexpr auto GCPCredentials = 
core::PropertyDefinitionBuilder<>::createProperty("GCP Credentials Provider 
Service")
       .withDescription("The Controller Service used to obtain Google Cloud 
Platform credentials. Should be the name of a GCPCredentialsControllerService.")
       .isRequired(true)
-      .withAllowedTypes({core::className<GCPCredentialsControllerService>()})
+      .withAllowedTypes<GCPCredentialsControllerService>()
       .build();
   EXTENSIONAPI static constexpr auto NumberOfRetries = 
core::PropertyDefinitionBuilder<>::createProperty("Number of retries")
       .withDescription("How many retry attempts should be made before routing 
to the failure relationship.")
diff --git a/extensions/http-curl/processors/InvokeHTTP.h 
b/extensions/http-curl/processors/InvokeHTTP.h
index c9d291a34..99a6a8968 100644
--- a/extensions/http-curl/processors/InvokeHTTP.h
+++ b/extensions/http-curl/processors/InvokeHTTP.h
@@ -103,10 +103,10 @@ class InvokeHTTP : public core::Processor {
   EXTENSIONAPI static constexpr auto AttributesToSend = 
core::PropertyDefinitionBuilder<>::createProperty("Attributes to Send")
       .withDescription("Regular expression that defines which attributes to 
send as HTTP headers in the request. If not defined, no attributes are sent as 
headers.")
       .build();
-  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 1, 0, 1>::createProperty("SSL Context 
Service")
+  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("SSL Context Service")
       .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
       .isRequired(false)
-      
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
       .withExclusiveOfProperties({{{"Remote URL", "^http:.*$"}}})
       .build();
   EXTENSIONAPI static constexpr auto ProxyHost = 
core::PropertyDefinitionBuilder<>::createProperty("Proxy Host")
diff --git a/extensions/librdkafka/KafkaProcessorBase.h 
b/extensions/librdkafka/KafkaProcessorBase.h
index eecc3f2fc..6e88c6689 100644
--- a/extensions/librdkafka/KafkaProcessorBase.h
+++ b/extensions/librdkafka/KafkaProcessorBase.h
@@ -47,37 +47,37 @@ enum class SASLMechanismOption {
 
 class KafkaProcessorBase : public core::Processor {
  public:
-  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
-        .withDescription("SSL Context Service Name")
-        
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
-        .build();
+  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
+      .withDescription("SSL Context Service Name")
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .build();
   EXTENSIONAPI static constexpr auto SecurityProtocol = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<kafka::SecurityProtocolOption>()>::createProperty("Security
 Protocol")
-        .withDescription("Protocol used to communicate with brokers. 
Corresponds to Kafka's 'security.protocol' property.")
-        
.withDefaultValue(magic_enum::enum_name(kafka::SecurityProtocolOption::plaintext))
-        
.withAllowedValues(magic_enum::enum_names<kafka::SecurityProtocolOption>())
-        .isRequired(true)
-        .build();
+      .withDescription("Protocol used to communicate with brokers. Corresponds 
to Kafka's 'security.protocol' property.")
+      
.withDefaultValue(magic_enum::enum_name(kafka::SecurityProtocolOption::plaintext))
+      
.withAllowedValues(magic_enum::enum_names<kafka::SecurityProtocolOption>())
+      .isRequired(true)
+      .build();
   EXTENSIONAPI static constexpr auto KerberosServiceName = 
core::PropertyDefinitionBuilder<>::createProperty("Kerberos Service Name")
-        .withDescription("Kerberos Service Name")
-        .build();
+      .withDescription("Kerberos Service Name")
+      .build();
   EXTENSIONAPI static constexpr auto KerberosPrincipal = 
core::PropertyDefinitionBuilder<>::createProperty("Kerberos Principal")
-        .withDescription("Kerberos Principal")
-        .build();
+      .withDescription("Kerberos Principal")
+      .build();
   EXTENSIONAPI static constexpr auto KerberosKeytabPath = 
core::PropertyDefinitionBuilder<>::createProperty("Kerberos Keytab Path")
-        .withDescription("The path to the location on the local filesystem 
where the kerberos keytab is located. Read permission on the file is required.")
-        .build();
+      .withDescription("The path to the location on the local filesystem where 
the kerberos keytab is located. Read permission on the file is required.")
+      .build();
   EXTENSIONAPI static constexpr auto SASLMechanism = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<kafka::SASLMechanismOption>()>::createProperty("SASL
 Mechanism")
-        .withDescription("The SASL mechanism to use for authentication. 
Corresponds to Kafka's 'sasl.mechanism' property.")
-        
.withDefaultValue(magic_enum::enum_name(kafka::SASLMechanismOption::GSSAPI))
-        
.withAllowedValues(magic_enum::enum_names<kafka::SASLMechanismOption>())
-        .isRequired(true)
-        .build();
+      .withDescription("The SASL mechanism to use for authentication. 
Corresponds to Kafka's 'sasl.mechanism' property.")
+      
.withDefaultValue(magic_enum::enum_name(kafka::SASLMechanismOption::GSSAPI))
+      .withAllowedValues(magic_enum::enum_names<kafka::SASLMechanismOption>())
+      .isRequired(true)
+      .build();
   EXTENSIONAPI static constexpr auto Username = 
core::PropertyDefinitionBuilder<>::createProperty("Username")
-        .withDescription("The username when the SASL Mechanism is 
sasl_plaintext")
-        .build();
+      .withDescription("The username when the SASL Mechanism is 
sasl_plaintext")
+      .build();
   EXTENSIONAPI static constexpr auto Password = 
core::PropertyDefinitionBuilder<>::createProperty("Password")
-        .withDescription("The password for the given username when the SASL 
Mechanism is sasl_plaintext")
-        .build();
+      .withDescription("The password for the given username when the SASL 
Mechanism is sasl_plaintext")
+      .build();
   EXTENSIONAPI static constexpr auto Properties = 
std::array<core::PropertyReference, 8>{
       SSLContextService,
       SecurityProtocol,
@@ -92,14 +92,14 @@ class KafkaProcessorBase : public core::Processor {
 
   KafkaProcessorBase(std::string name, const utils::Identifier& uuid, 
std::shared_ptr<core::logging::Logger> logger)
       : core::Processor(std::move(name), uuid),
-        logger_(logger) {
+        logger_(std::move(logger)) {
   }
 
  protected:
   virtual std::optional<utils::net::SslData> getSslData(core::ProcessContext& 
context) const;
   void setKafkaAuthenticationParameters(core::ProcessContext& context, 
gsl::not_null<rd_kafka_conf_t*> config);
 
-  kafka::SecurityProtocolOption security_protocol_;
+  kafka::SecurityProtocolOption security_protocol_{};
   std::shared_ptr<core::logging::Logger> logger_;
 };
 
diff --git a/extensions/splunk/SplunkHECProcessor.h 
b/extensions/splunk/SplunkHECProcessor.h
index e33a2bf92..bc885ac13 100644
--- a/extensions/splunk/SplunkHECProcessor.h
+++ b/extensions/splunk/SplunkHECProcessor.h
@@ -36,29 +36,29 @@ namespace org::apache::nifi::minifi::extensions::splunk {
 class SplunkHECProcessor : public core::Processor {
  public:
   EXTENSIONAPI static constexpr auto Hostname = 
core::PropertyDefinitionBuilder<>::createProperty("Hostname")
-    .withDescription("The ip address or hostname of the Splunk server.")
-    .isRequired(true)
-    .build();
+      .withDescription("The ip address or hostname of the Splunk server.")
+      .isRequired(true)
+      .build();
   EXTENSIONAPI static constexpr auto Port = 
core::PropertyDefinitionBuilder<>::createProperty("Port")
-    .withDescription("The HTTP Event Collector HTTP Port Number.")
-    .withPropertyType(core::StandardPropertyTypes::PORT_TYPE)
-    .withDefaultValue("8088")
-    .isRequired(true)
-    .build();
+      .withDescription("The HTTP Event Collector HTTP Port Number.")
+      .withPropertyType(core::StandardPropertyTypes::PORT_TYPE)
+      .withDefaultValue("8088")
+      .isRequired(true)
+      .build();
   EXTENSIONAPI static constexpr auto Token = 
core::PropertyDefinitionBuilder<>::createProperty("Token")
-    .withDescription("HTTP Event Collector token starting with the string 
Splunk. For example \'Splunk 1234578-abcd-1234-abcd-1234abcd\'")
-    .isRequired(true)
-    .build();
+      .withDescription("HTTP Event Collector token starting with the string 
Splunk. For example \'Splunk 1234578-abcd-1234-abcd-1234abcd\'")
+      .isRequired(true)
+      .build();
   EXTENSIONAPI static constexpr auto SplunkRequestChannel = 
core::PropertyDefinitionBuilder<>::createProperty("Splunk Request Channel")
-    .withDescription("Identifier of the used request channel.")
-    .isRequired(true)
-    .build();
-  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 1, 0, 1>::createProperty("SSL Context 
Service")
-    .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
-    .isRequired(false)
-    .withExclusiveOfProperties({{{"Hostname", "^http:.*$"}}})
-    
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
-    .build();
+      .withDescription("Identifier of the used request channel.")
+      .isRequired(true)
+      .build();
+  EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("SSL Context Service")
+      .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
+      .isRequired(false)
+      .withExclusiveOfProperties({{{"Hostname", "^http:.*$"}}})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .build();
   EXTENSIONAPI static constexpr auto Properties = 
std::array<core::PropertyReference, 5>{
       Hostname,
       Port,
diff --git a/extensions/standard-processors/processors/GetTCP.h 
b/extensions/standard-processors/processors/GetTCP.h
index 5846956be..184da62df 100644
--- a/extensions/standard-processors/processors/GetTCP.h
+++ b/extensions/standard-processors/processors/GetTCP.h
@@ -69,9 +69,9 @@ class GetTCP : public core::Processor {
       .withDescription("A comma delimited list of the endpoints to connect to. 
The format should be <server_address>:<port>.")
       .isRequired(true)
       .build();
-  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
+  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("SSL Context Service Name")
-      
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
       .build();
   EXTENSIONAPI static constexpr auto MessageDelimiter = 
core::PropertyDefinitionBuilder<>::createProperty("Message Delimiter")
       .withDescription("Character that denotes the end of the message.")
diff --git a/extensions/standard-processors/processors/ListenSyslog.h 
b/extensions/standard-processors/processors/ListenSyslog.h
index 3f975cb2c..0f172e35e 100644
--- a/extensions/standard-processors/processors/ListenSyslog.h
+++ b/extensions/standard-processors/processors/ListenSyslog.h
@@ -75,10 +75,10 @@ class ListenSyslog : public NetworkListenerProcessor {
       .withPropertyType(core::StandardPropertyTypes::UNSIGNED_LONG_TYPE)
       .withDefaultValue("10000")
       .build();
-  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
+  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be received over a secure 
connection. "
           "This Property is only considered if the <Protocol> Property has a 
value of \"TCP\".")
-      
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
       .build();
   EXTENSIONAPI static constexpr auto ClientAuth = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client
 Auth")
       .withDescription("The client authentication policy to use for the SSL 
Context. Only used if an SSL Context Service is provided.")
diff --git a/extensions/standard-processors/processors/ListenTCP.h 
b/extensions/standard-processors/processors/ListenTCP.h
index 9f096838a..79d13fa1b 100644
--- a/extensions/standard-processors/processors/ListenTCP.h
+++ b/extensions/standard-processors/processors/ListenTCP.h
@@ -60,9 +60,9 @@ class ListenTCP : public NetworkListenerProcessor {
       .withDefaultValue("10000")
       .isRequired(true)
       .build();
-  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
+  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be received over a secure 
connection.")
-      
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
       .build();
   EXTENSIONAPI static constexpr auto ClientAuth = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client
 Auth")
       .withDescription("The client authentication policy to use for the SSL 
Context. Only used if an SSL Context Service is provided.")
diff --git a/extensions/standard-processors/processors/PutFile.h 
b/extensions/standard-processors/processors/PutFile.h
index 26d49571b..9067a1f6c 100644
--- a/extensions/standard-processors/processors/PutFile.h
+++ b/extensions/standard-processors/processors/PutFile.h
@@ -71,7 +71,7 @@ class PutFile : public core::Processor {
       .withAllowedValues({CONFLICT_RESOLUTION_STRATEGY_FAIL, 
CONFLICT_RESOLUTION_STRATEGY_IGNORE, CONFLICT_RESOLUTION_STRATEGY_REPLACE})
       .withDefaultValue(CONFLICT_RESOLUTION_STRATEGY_FAIL)
       .build();
-  EXTENSIONAPI static constexpr auto CreateDirs = 
core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Create Missing 
Directories")
+  EXTENSIONAPI static constexpr auto CreateDirs = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("Create Missing 
Directories")
       .withDescription("If true, then missing destination directories will be 
created. If false, flowfiles are penalized and sent to failure.")
       .withDefaultValue("true")
       .isRequired(true)
diff --git a/extensions/standard-processors/processors/PutTCP.h 
b/extensions/standard-processors/processors/PutTCP.h
index 923f90a24..5063bae67 100644
--- a/extensions/standard-processors/processors/PutTCP.h
+++ b/extensions/standard-processors/processors/PutTCP.h
@@ -63,55 +63,55 @@ class PutTCP final : public core::Processor {
       "An optional \"Connection Per FlowFile\" parameter can be specified to 
change the behaviour so that each FlowFiles content is transmitted over a 
single TCP connection "
       "which is closed after the FlowFile has been sent.";
 
-EXTENSIONAPI static constexpr auto Hostname = 
core::PropertyDefinitionBuilder<>::createProperty("Hostname")
-    .withDescription("The ip address or hostname of the destination.")
-    .withDefaultValue("localhost")
-    .isRequired(true)
-    .supportsExpressionLanguage(true)
-    .build();
-EXTENSIONAPI static constexpr auto Port = 
core::PropertyDefinitionBuilder<>::createProperty("Port")
-    .withDescription("The port or service on the destination.")
-    .isRequired(true)
-    .supportsExpressionLanguage(true)
-    .build();
-EXTENSIONAPI static constexpr auto IdleConnectionExpiration = 
core::PropertyDefinitionBuilder<>::createProperty("Idle Connection Expiration")
-    .withDescription("The amount of time a connection should be held open 
without being used before closing the connection. A value of 0 seconds will 
disable this feature.")
-    .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE)
-    .withDefaultValue("15 seconds")
-    .isRequired(true)
-    .supportsExpressionLanguage(true)
-    .build();
-EXTENSIONAPI static constexpr auto Timeout = 
core::PropertyDefinitionBuilder<>::createProperty("Timeout")
-    .withDescription("The timeout for connecting to and communicating with the 
destination.")
-    .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE)
-    .withDefaultValue("15 seconds")
-    .isRequired(true)
-    .supportsExpressionLanguage(true)
-    .build();
-EXTENSIONAPI static constexpr auto ConnectionPerFlowFile = 
core::PropertyDefinitionBuilder<>::createProperty("Connection Per FlowFile")
-    .withDescription("Specifies whether to send each FlowFile's content on an 
individual connection.")
-    .withPropertyType(core::StandardPropertyTypes::BOOLEAN_TYPE)
-    .withDefaultValue("false")
-    .isRequired(true)
-    .supportsExpressionLanguage(false)
-    .build();
-EXTENSIONAPI static constexpr auto OutgoingMessageDelimiter = 
core::PropertyDefinitionBuilder<>::createProperty("Outgoing Message Delimiter")
-    .withDescription("Specifies the delimiter to use when sending messages out 
over the same TCP stream. "
-        "The delimiter is appended to each FlowFile message that is 
transmitted over the stream so that the receiver can determine when one message 
ends and the next message begins. "
-        "Users should ensure that the FlowFile content does not contain the 
delimiter character to avoid errors.")
-    .isRequired(false)
-    .supportsExpressionLanguage(true)
-    .build();
-EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service")
-    .withDescription("The Controller Service to use in order to obtain an SSL 
Context. If this property is set, messages will be sent over a secure 
connection.")
-    .isRequired(false)
-    
.withAllowedTypes({core::className<minifi::controllers::SSLContextService>()})
-    .build();
-EXTENSIONAPI static constexpr auto MaxSizeOfSocketSendBuffer = 
core::PropertyDefinitionBuilder<>::createProperty("Max Size of Socket Send 
Buffer")
-    .withDescription("The maximum size of the socket send buffer that should 
be used. This is a suggestion to the Operating System to indicate how big the 
socket buffer should be.")
-    .isRequired(false)
-    .withPropertyType(core::StandardPropertyTypes::DATA_SIZE_TYPE)
-    .build();
+  EXTENSIONAPI static constexpr auto Hostname = 
core::PropertyDefinitionBuilder<>::createProperty("Hostname")
+      .withDescription("The ip address or hostname of the destination.")
+      .withDefaultValue("localhost")
+      .isRequired(true)
+      .supportsExpressionLanguage(true)
+      .build();
+  EXTENSIONAPI static constexpr auto Port = 
core::PropertyDefinitionBuilder<>::createProperty("Port")
+      .withDescription("The port or service on the destination.")
+      .isRequired(true)
+      .supportsExpressionLanguage(true)
+      .build();
+  EXTENSIONAPI static constexpr auto IdleConnectionExpiration = 
core::PropertyDefinitionBuilder<>::createProperty("Idle Connection Expiration")
+      .withDescription("The amount of time a connection should be held open 
without being used before closing the connection. A value of 0 seconds will 
disable this feature.")
+      .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE)
+      .withDefaultValue("15 seconds")
+      .isRequired(true)
+      .supportsExpressionLanguage(true)
+      .build();
+  EXTENSIONAPI static constexpr auto Timeout = 
core::PropertyDefinitionBuilder<>::createProperty("Timeout")
+      .withDescription("The timeout for connecting to and communicating with 
the destination.")
+      .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE)
+      .withDefaultValue("15 seconds")
+      .isRequired(true)
+      .supportsExpressionLanguage(true)
+      .build();
+  EXTENSIONAPI static constexpr auto ConnectionPerFlowFile = 
core::PropertyDefinitionBuilder<>::createProperty("Connection Per FlowFile")
+      .withDescription("Specifies whether to send each FlowFile's content on 
an individual connection.")
+      .withPropertyType(core::StandardPropertyTypes::BOOLEAN_TYPE)
+      .withDefaultValue("false")
+      .isRequired(true)
+      .supportsExpressionLanguage(false)
+      .build();
+  EXTENSIONAPI static constexpr auto OutgoingMessageDelimiter = 
core::PropertyDefinitionBuilder<>::createProperty("Outgoing Message Delimiter")
+      .withDescription("Specifies the delimiter to use when sending messages 
out over the same TCP stream. "
+          "The delimiter is appended to each FlowFile message that is 
transmitted over the stream so that the receiver can determine when one message 
ends and the next message begins. "
+          "Users should ensure that the FlowFile content does not contain the 
delimiter character to avoid errors.")
+      .isRequired(false)
+      .supportsExpressionLanguage(true)
+      .build();
+  EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
+      .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be sent over a secure 
connection.")
+      .isRequired(false)
+      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .build();
+  EXTENSIONAPI static constexpr auto MaxSizeOfSocketSendBuffer = 
core::PropertyDefinitionBuilder<>::createProperty("Max Size of Socket Send 
Buffer")
+      .withDescription("The maximum size of the socket send buffer that should 
be used. This is a suggestion to the Operating System to indicate how big the 
socket buffer should be.")
+      .isRequired(false)
+      .withPropertyType(core::StandardPropertyTypes::DATA_SIZE_TYPE)
+      .build();
   EXTENSIONAPI static constexpr auto Properties = 
std::array<core::PropertyReference, 8>{
       Hostname,
       Port,
diff --git a/extensions/standard-processors/processors/TailFile.h 
b/extensions/standard-processors/processors/TailFile.h
index 809d80fdc..015eab7d9 100644
--- a/extensions/standard-processors/processors/TailFile.h
+++ b/extensions/standard-processors/processors/TailFile.h
@@ -179,9 +179,9 @@ class TailFile : public core::Processor {
       
.withDefaultValue(magic_enum::enum_name(InitialStartPositions::BEGINNING_OF_FILE))
       .withAllowedValues(magic_enum::enum_names<InitialStartPositions>())
       .build();
-  EXTENSIONAPI static constexpr auto AttributeProviderService = 
core::PropertyDefinitionBuilder<0, 1>::createProperty("Attribute Provider 
Service")
+  EXTENSIONAPI static constexpr auto AttributeProviderService = 
core::PropertyDefinitionBuilder<>::createProperty("Attribute Provider Service")
       .withDescription("Provides a list of key-value pair records which can be 
used in the Base Directory property using Expression Language. Requires 
Multiple file mode.")
-      
.withAllowedTypes({core::className<minifi::controllers::AttributeProviderService>()})
+      .withAllowedTypes<minifi::controllers::AttributeProviderService>()
       .build();
   EXTENSIONAPI static constexpr auto BatchSize = 
core::PropertyDefinitionBuilder<>::createProperty("Batch Size")
       .withDescription("Maximum number of flowfiles emitted in a single 
trigger. If set to 0 all new content will be processed.")
diff --git 
a/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp 
b/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp
index be7a60c97..deac64ba4 100644
--- a/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp
+++ b/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp
@@ -585,7 +585,7 @@ TEST_CASE("Test Dependent Property", 
"[YamlConfigurationDependentProperty]") {
   const auto component = std::make_shared<DummyComponent>();
   component->setSupportedProperties(std::array<core::PropertyReference, 2>{
     core::PropertyDefinitionBuilder<>::createProperty("Prop 
A").withDescription("Prop A desc").withDefaultValue("val 
A").isRequired(true).build(),
-    core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val 
B").isRequired(true).withDependentProperties({ "Prop A" }).build()
+    core::PropertyDefinitionBuilder<0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val 
B").isRequired(true).withDependentProperties({ "Prop A" }).build()
   });
   yamlConfig.validateComponentProperties(*component, "component A", "section 
A");
   REQUIRE(true);  // Expected to get here w/o any exceptions
@@ -598,7 +598,7 @@ TEST_CASE("Test Dependent Property 2", 
"[YamlConfigurationDependentProperty2]")
   const auto component = std::make_shared<DummyComponent>();
   component->setSupportedProperties(std::array<core::PropertyReference, 2>{
     core::PropertyDefinitionBuilder<>::createProperty("Prop 
A").withDescription("Prop A desc").isRequired(false).build(),
-    core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val 
B").isRequired(true).withDependentProperties({ "Prop A" }).build()
+    core::PropertyDefinitionBuilder<0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val 
B").isRequired(true).withDependentProperties({ "Prop A" }).build()
   });
   bool config_failed = false;
   try {
@@ -619,7 +619,7 @@ TEST_CASE("Test Exclusive Property", 
"[YamlConfigurationExclusiveOfProperty]") {
   const auto component = std::make_shared<DummyComponent>();
   component->setSupportedProperties(std::array<core::PropertyReference, 2>{
     core::PropertyDefinitionBuilder<>::createProperty("Prop 
A").withDescription("Prop A desc").withDefaultValue("val 
A").isRequired(true).build(),
-    core::PropertyDefinitionBuilder<0, 0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true)
+    core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true)
         .withExclusiveOfProperties({{ { "Prop A", "^abcd.*$" } }}).build()
   });
   yamlConfig.validateComponentProperties(*component, "component A", "section 
A");
@@ -633,7 +633,7 @@ TEST_CASE("Test Exclusive Property 2", 
"[YamlConfigurationExclusiveOfProperty2]"
   const auto component = std::make_shared<DummyComponent>();
   component->setSupportedProperties(std::array<core::PropertyReference, 2>{
     core::PropertyDefinitionBuilder<>::createProperty("Prop 
A").withDescription("Prop A desc").withDefaultValue("val 
A").isRequired(true).build(),
-    core::PropertyDefinitionBuilder<0, 0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true)
+    core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop 
B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true)
         .withExclusiveOfProperties({{ { "Prop A", "^val.*$" } }}).build()
   });
   bool config_failed = false;
diff --git a/libminifi/include/core/OutputAttributeDefinition.h 
b/libminifi/include/core/OutputAttributeDefinition.h
index 1057c72db..9e4ea9c67 100644
--- a/libminifi/include/core/OutputAttributeDefinition.h
+++ b/libminifi/include/core/OutputAttributeDefinition.h
@@ -17,9 +17,9 @@
 #pragma once
 
 #include <array>
+#include <span>
 #include <string_view>
 
-#include "utils/gsl.h"
 #include "RelationshipDefinition.h"
 
 namespace org::apache::nifi::minifi::core {
@@ -48,7 +48,7 @@ struct OutputAttributeReference {
   }
 
   std::string_view name;
-  gsl::span<const RelationshipDefinition> relationships;
+  std::span<const RelationshipDefinition> relationships;
   std::string_view description;
 };
 
diff --git a/libminifi/include/core/PropertyDefinition.h 
b/libminifi/include/core/PropertyDefinition.h
index 99022855d..1af98de75 100644
--- a/libminifi/include/core/PropertyDefinition.h
+++ b/libminifi/include/core/PropertyDefinition.h
@@ -18,22 +18,24 @@
 
 #include <array>
 #include <optional>
+#include <span>
 #include <string_view>
 #include <utility>
 
+#include "core/Core.h"
 #include "core/PropertyType.h"
 #include "utils/gsl.h"
 
 namespace org::apache::nifi::minifi::core {
 
-template<size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t 
NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0>
+template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, 
size_t NumExclusiveOfProperties = 0>
 struct PropertyDefinition {
   std::string_view name;
   std::string_view display_name;
   std::string_view description;
   bool is_required = false;
   std::array<std::string_view, NumAllowedValues> allowed_values;
-  std::array<std::string_view, NumAllowedTypes> allowed_types;
+  std::span<const std::string_view> allowed_types;
   std::array<std::string_view, NumDependentProperties> dependent_properties;
   std::array<std::pair<std::string_view, std::string_view>, 
NumExclusiveOfProperties> exclusive_of_properties;
   std::optional<std::string_view> default_value;
@@ -46,18 +48,18 @@ struct PropertyReference {
   std::string_view display_name;
   std::string_view description;
   bool is_required = false;
-  gsl::span<const std::string_view> allowed_values;
-  gsl::span<const std::string_view> allowed_types;
-  gsl::span<const std::string_view> dependent_properties;
-  gsl::span<const std::pair<std::string_view, std::string_view>> 
exclusive_of_properties;
+  std::span<const std::string_view> allowed_values;
+  std::span<const std::string_view> allowed_types;
+  std::span<const std::string_view> dependent_properties;
+  std::span<const std::pair<std::string_view, std::string_view>> 
exclusive_of_properties;
   std::optional<std::string_view> default_value;
   gsl::not_null<const PropertyType*> type = 
gsl::make_not_null(&StandardPropertyTypes::VALID_TYPE);
   bool supports_expression_language = false;
 
   constexpr PropertyReference() = default;
 
-  template<size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t 
NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0>
-  constexpr PropertyReference(const PropertyDefinition<NumAllowedValues, 
NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties>& 
property_definition)  // NOLINT: non-explicit on purpose
+  template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, 
size_t NumExclusiveOfProperties = 0>
+  constexpr PropertyReference(const PropertyDefinition<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties>& property_definition)  // 
NOLINT: non-explicit on purpose
     : name{property_definition.name},
       display_name{property_definition.display_name},
       description{property_definition.description},
diff --git a/libminifi/include/core/PropertyDefinitionBuilder.h 
b/libminifi/include/core/PropertyDefinitionBuilder.h
index 801faf59e..4ec16838a 100644
--- a/libminifi/include/core/PropertyDefinitionBuilder.h
+++ b/libminifi/include/core/PropertyDefinitionBuilder.h
@@ -23,75 +23,80 @@
 
 namespace org::apache::nifi::minifi::core {
 
-template <size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t 
NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0>
+namespace detail {
+template<typename... Types>
+inline constexpr auto TypeNames = std::array<std::string_view, 
sizeof...(Types)>{core::className<Types>()...};
+}
+
+template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, 
size_t NumExclusiveOfProperties = 0>
 struct PropertyDefinitionBuilder {
-  static constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> 
createProperty(std::string_view name) {
-    PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> builder;
+  static constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> 
createProperty(std::string_view name) {
+    PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, 
NumExclusiveOfProperties> builder;
     builder.property.name = name;
     return builder;
   }
 
-  static constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> 
createProperty(std::string_view name, std::string_view display_name) {
-    PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> builder;
+  static constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> 
createProperty(std::string_view name, std::string_view display_name) {
+    PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, 
NumExclusiveOfProperties> builder;
     builder.property.name = name;
     builder.property.display_name = display_name;
     return builder;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> 
withDescription(std::string_view description) {
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> 
withDescription(std::string_view description) {
     property.description = description;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> isRequired(bool required) {
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> isRequired(bool required) {
     property.is_required = required;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> 
supportsExpressionLanguage(bool supports_expression_language) {
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> 
supportsExpressionLanguage(bool supports_expression_language) {
     property.supports_expression_language = supports_expression_language;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> 
withDefaultValue(std::string_view default_value) {
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> 
withDefaultValue(std::string_view default_value) {
     property.default_value = std::optional<std::string_view>{default_value};  
// workaround for gcc 11.1; on gcc 11.3 and later, `property.default_value = 
default_value` works, too
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> withAllowedValues(
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> withAllowedValues(
       std::array<std::string_view, NumAllowedValues> allowed_values) {
     property.allowed_values = allowed_values;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> withAllowedTypes(
-      std::array<std::string_view, NumAllowedTypes> types) {
-    property.allowed_types = types;
+  template<typename... AllowedTypes>
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> withAllowedTypes() {
+    property.allowed_types = {detail::TypeNames<AllowedTypes...>};
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> withDependentProperties(
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> withDependentProperties(
       std::array<std::string_view, NumDependentProperties> 
dependent_properties) {
     property.dependent_properties = dependent_properties;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> withExclusiveOfProperties(
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> withExclusiveOfProperties(
       std::array<std::pair<std::string_view, std::string_view>, 
NumExclusiveOfProperties> exclusive_of_properties) {
     property.exclusive_of_properties = exclusive_of_properties;
     return *this;
   }
 
-  constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> withPropertyType(const 
PropertyType& property_type) {
+  constexpr PropertyDefinitionBuilder<NumAllowedValues, 
NumDependentProperties, NumExclusiveOfProperties> withPropertyType(const 
PropertyType& property_type) {
     property.type = gsl::make_not_null(&property_type);
     return *this;
   }
 
-  constexpr PropertyDefinition<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> build() {
+  constexpr PropertyDefinition<NumAllowedValues, NumDependentProperties, 
NumExclusiveOfProperties> build() {
     return property;
   }
 
-  PropertyDefinition<NumAllowedValues, NumAllowedTypes, 
NumDependentProperties, NumExclusiveOfProperties> property{};
+  PropertyDefinition<NumAllowedValues, NumDependentProperties, 
NumExclusiveOfProperties> property{};
 };
 
 }  // namespace org::apache::nifi::minifi::core
diff --git a/libminifi/src/core/Property.cpp b/libminifi/src/core/Property.cpp
index 017deaffb..79f5fc488 100644
--- a/libminifi/src/core/Property.cpp
+++ b/libminifi/src/core/Property.cpp
@@ -91,18 +91,18 @@ std::vector<std::pair<std::string, std::string>> 
Property::getExclusiveOfPropert
 }
 
 namespace {
-std::vector<PropertyValue> createPropertyValues(gsl::span<const 
std::string_view> values, const core::PropertyParser& property_parser) {
+std::vector<PropertyValue> createPropertyValues(std::span<const 
std::string_view> values, const core::PropertyParser& property_parser) {
   return ranges::views::transform(values, [&property_parser](const auto& 
value) {
     return property_parser.parse(value);
   }) | ranges::to<std::vector>;
 }
 
-inline std::vector<std::string> createStrings(gsl::span<const 
std::string_view> string_views) {
+inline std::vector<std::string> createStrings(std::span<const 
std::string_view> string_views) {
   return ranges::views::transform(string_views, [](const auto& string_view) { 
return std::string{string_view}; })
       | ranges::to<std::vector>;
 }
 
-inline std::vector<std::pair<std::string, std::string>> 
createStrings(gsl::span<const std::pair<std::string_view, std::string_view>> 
pairs_of_string_views) {
+inline std::vector<std::pair<std::string, std::string>> 
createStrings(std::span<const std::pair<std::string_view, std::string_view>> 
pairs_of_string_views) {
   return ranges::views::transform(pairs_of_string_views, [](const auto& 
pair_of_string_views) { return std::pair<std::string, 
std::string>(pair_of_string_views); })
       | ranges::to<std::vector>;
 }
diff --git a/libminifi/test/unit/ComponentManifestTests.cpp 
b/libminifi/test/unit/ComponentManifestTests.cpp
index 4f5c24737..907300750 100644
--- a/libminifi/test/unit/ComponentManifestTests.cpp
+++ b/libminifi/test/unit/ComponentManifestTests.cpp
@@ -61,10 +61,10 @@ class ExampleProcessor : public core::Processor {
   using Processor::Processor;
 
   static constexpr const char* Description = "An example processor";
-  static constexpr auto ExampleProperty = core::PropertyDefinitionBuilder<0, 
1>::createProperty("Example Property")
+  static constexpr auto ExampleProperty = 
core::PropertyDefinitionBuilder<>::createProperty("Example Property")
       .withDescription("An example property")
       .isRequired(false)
-      .withAllowedTypes({core::className<ExampleService>()})
+      .withAllowedTypes<ExampleService>()
       .build();
   static constexpr auto Properties = std::array<core::PropertyReference, 
1>{ExampleProperty};
   static constexpr auto Relationships = 
std::array<core::RelationshipDefinition, 0>{};
diff --git a/libminifi/test/unit/TypeListTests.cpp 
b/libminifi/test/unit/TypeListTests.cpp
new file mode 100644
index 000000000..463a7a26c
--- /dev/null
+++ b/libminifi/test/unit/TypeListTests.cpp
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../Catch.h"
+#include "core/Core.h"
+#include "utils/meta/type_list.h"
+
+class A {};
+
+namespace outer {
+class B {};
+class C {};
+
+namespace inner {
+class C {};
+class D {};
+}
+}
+
+template<typename... Types>
+using type_list = org::apache::nifi::minifi::utils::meta::type_list<Types...>;
+
+TEST_CASE("an empty type_list doesn't contain anything") {
+  STATIC_CHECK_FALSE(type_list<>::contains<A>());
+  STATIC_CHECK_FALSE(type_list<>::contains<outer::B>());
+  STATIC_CHECK_FALSE(type_list<>::contains<outer::inner::D>());
+  STATIC_CHECK_FALSE(type_list<>::contains<std::string>());
+}
+
+TEST_CASE("a non-empty type_list contains what it should") {
+  STATIC_CHECK(type_list<A, outer::B>::contains<A>());
+  STATIC_CHECK(type_list<A, outer::B>::contains<outer::B>());
+  STATIC_CHECK_FALSE(type_list<A, outer::B>::contains<outer::C>());
+  STATIC_CHECK_FALSE(type_list<A, outer::B>::contains<outer::inner::D>());
+
+  STATIC_CHECK(type_list<int, A, std::string>::contains<int>());
+  STATIC_CHECK(type_list<int, A, std::string>::contains<A>());
+  STATIC_CHECK(type_list<int, A, std::string>::contains<std::string>());
+  STATIC_CHECK_FALSE(type_list<int, A, std::string>::contains<double>());
+  STATIC_CHECK_FALSE(type_list<int, A, std::string>::contains<outer::C>());
+
+  namespace inner = outer::inner;
+  STATIC_CHECK(type_list<outer::C>::contains<outer::C>());
+  STATIC_CHECK(type_list<inner::C>::contains<inner::C>());
+  STATIC_CHECK_FALSE(type_list<outer::C>::contains<inner::C>());
+  STATIC_CHECK_FALSE(type_list<inner::C>::contains<outer::C>());
+}


Reply via email to