diff --git a/internal/native/message_server.go b/internal/native/message_server.go index 8102e7370..4afa4ce27 100644 --- a/internal/native/message_server.go +++ b/internal/native/message_server.go @@ -1,99 +1,7 @@ package native /* -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -/// Wraps a Pact model struct -typedef struct InteractionHandle InteractionHandle; -typedef struct PactMessageIterator PactMessageIterator; -typedef struct SynchronousMessage SynchronousMessage; -typedef struct Message Message; - -struct InteractionHandle { - unsigned int interaction_ref; -}; - -/// Wraps a Pact model struct -typedef struct PactHandle PactHandle; -struct PactHandle { - unsigned int pact_ref; -}; - -PactHandle pactffi_new_message_pact(const char *consumer_name, const char *provider_name); -InteractionHandle pactffi_new_message(PactHandle pact, const char *description); -// Creates a new synchronous message interaction (request/response) and return a handle to it -InteractionHandle pactffi_new_sync_message_interaction(PactHandle pact, const char *description); -// Creates a new asynchronous message interaction (request/response) and return a handle to it -InteractionHandle pactffi_new_message_interaction(PactHandle pact, const char *description); -void pactffi_message_expects_to_receive(InteractionHandle message, const char *description); -void pactffi_message_given(InteractionHandle message, const char *description); -void pactffi_message_given_with_param(InteractionHandle message, const char *description, const char *name, const char *value); -void pactffi_message_with_contents(InteractionHandle message, const char *content_type, const char *body, int size); -void pactffi_message_with_metadata(InteractionHandle message, const char *key, const char *value); -int pactffi_write_message_pact_file(PactHandle pact, const char *directory, bool overwrite); -void pactffi_with_message_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value); -int pactffi_write_pact_file(int mock_server_port, const char *directory, bool overwrite); -bool pactffi_given(InteractionHandle interaction, const char *description); -bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value); -void pactffi_with_specification(PactHandle pact, int specification_version); - -int pactffi_using_plugin(PactHandle pact, const char *plugin_name, const char *plugin_version); -void pactffi_cleanup_plugins(PactHandle pact); -int pactffi_interaction_contents(InteractionHandle interaction, int interaction_part, const char *content_type, const char *contents); - -// Create a mock server for the provided Pact handle and transport. -int pactffi_create_mock_server_for_transport(PactHandle pact, const char *addr, int port, const char *transport, const char *transport_config); -bool pactffi_cleanup_mock_server(int mock_server_port); -char* pactffi_mock_server_mismatches(int mock_server_port); -bool pactffi_mock_server_matched(int mock_server_port); - -// Functions to get message contents - -// Get the length of the request contents of a `SynchronousMessage`. -size_t pactffi_sync_message_get_request_contents_length(SynchronousMessage *message); -struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact); -struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); - -// Async -// Get the length of the contents of a `Message`. -size_t pactffi_message_get_contents_length(Message *message); - -// Get the contents of a `Message` as a pointer to an array of bytes. -const unsigned char *pactffi_message_get_contents_bin(const Message *message); -struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact); -struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); - -// Need the index of the body to get -const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, size_t index); -size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, size_t index); - -// Sync -// Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes. -// The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`. -const unsigned char *pactffi_sync_message_get_request_contents_bin(SynchronousMessage *message); -// Set Sync message request body - non binary -void pactffi_sync_message_set_request_contents(InteractionHandle *message, const char *contents, const char *content_type); - -// Set Sync message request body - binary -void pactffi_sync_message_set_request_contents_bin(InteractionHandle *message, const unsigned char *contents, size_t len, const char *content_type); - -// Set sync message response contents - non binary -void pactffi_sync_message_set_response_contents(InteractionHandle *message, size_t index, const char *contents, const char *content_type); - -// Set sync message response contents - binary -void pactffi_sync_message_set_response_contents_bin(InteractionHandle *message, size_t index, const unsigned char *contents, size_t len, const char *content_type); - -// Can be used instead of the above as a general abstraction for non-binary bodies -bool pactffi_with_body(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body); - -// Can be used instead of the above as a general abstraction for binary bodies -// bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const uint8_t *body, size_t size); -bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, int size); +#include "pact.h" */ import "C" @@ -266,9 +174,9 @@ func (m *Message) WithRequestBinaryContents(body []byte) *Message { defer free(cHeader) // TODO: handle response - res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.uchar)(unsafe.Pointer(&body[0])), C.ulong(len(body))) - log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res)) + log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", bool(res)) return m } @@ -277,9 +185,9 @@ func (m *Message) WithRequestBinaryContentType(contentType string, body []byte) defer free(cHeader) // TODO: handle response - res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.uchar)(unsafe.Pointer(&body[0])), C.ulong(len(body))) - log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res)) + log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", res) return m } @@ -297,7 +205,7 @@ func (m *Message) WithResponseBinaryContents(body []byte) *Message { defer free(cHeader) // TODO: handle response - C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_RESPONSE), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_RESPONSE), cHeader, (*C.uchar)(unsafe.Pointer(&body[0])), C.ulong(len(body))) return m } @@ -316,7 +224,7 @@ func (m *Message) WithContents(part interactionPart, contentType string, body [] defer free(cHeader) res := C.pactffi_with_body(m.handle, C.int(part), cHeader, (*C.char)(unsafe.Pointer(&body[0]))) - log.Println("[DEBUG] response from pactffi_interaction_contents", (int(res) == 1)) + log.Println("[DEBUG] response from pactffi_interaction_contents", (bool(res))) return m } @@ -330,8 +238,8 @@ func (m *MessageServer) UsingPlugin(pluginName string, pluginVersion string) err cPluginVersion := C.CString(pluginVersion) defer free(cPluginVersion) - InstallSignalHandlers() r := C.pactffi_using_plugin(m.messagePact.handle, cPluginName, cPluginVersion) + InstallSignalHandlers() // 1 - A general panic was caught. // 2 - Failed to load the plugin. @@ -535,7 +443,7 @@ func (m *MessageServer) StartTransport(transport string, address string, port in cConfig := C.CString(configJson) defer free(cConfig) - p := C.pactffi_create_mock_server_for_transport(m.messagePact.handle, cAddress, C.int(port), cTransport, cConfig) + p := C.pactffi_create_mock_server_for_transport(m.messagePact.handle, cAddress, C.ushort(port), cTransport, cConfig) // | Error | Description // |-------|------------- @@ -578,7 +486,7 @@ func (m *MessageServer) CleanupMockServer(port int) bool { log.Println("[DEBUG] mock server cleaning up port:", port) res := C.pactffi_cleanup_mock_server(C.int(port)) - return int(res) == 1 + return bool(res) } // MockServerMismatchedRequests returns a JSON object containing any mismatches from @@ -616,7 +524,7 @@ func (m *MessageServer) MockServerMatched(port int) bool { // log.Println("MATCHED RES?") // log.Println(int(res)) - return int(res) == 1 + return bool(res) } // WritePactFile writes the Pact to file. @@ -625,12 +533,12 @@ func (m *MessageServer) WritePactFile(dir string, overwrite bool) error { cDir := C.CString(dir) defer free(cDir) - overwritePact := 0 + overwritePact := false if overwrite { - overwritePact = 1 + overwritePact = true } - res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.int(overwritePact))) + res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.bool(overwritePact))) /// | Error | Description | /// |-------|-------------| @@ -654,12 +562,12 @@ func (m *MessageServer) WritePactFileForServer(port int, dir string, overwrite b cDir := C.CString(dir) defer free(cDir) - overwritePact := 0 + overwritePact := false if overwrite { - overwritePact = 1 + overwritePact = true } - res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact))) + res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.bool(overwritePact))) /// | Error | Description | /// |-------|-------------| diff --git a/internal/native/mock_server.go b/internal/native/mock_server.go index d3adcfc85..0f13c22ab 100644 --- a/internal/native/mock_server.go +++ b/internal/native/mock_server.go @@ -1,165 +1,7 @@ package native /* -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -void pactffi_init(char* log); -char* pactffi_version(); - -/// Wraps a Pact model struct -typedef struct InteractionHandle InteractionHandle; - -struct InteractionHandle { - unsigned int interaction_ref; -}; - -typedef enum InteractionPart { - InteractionPart_Request, - InteractionPart_Response, -} InteractionPart; - -/// Wraps a Pact model struct -typedef struct PactHandle PactHandle; -struct PactHandle { - unsigned int pact_ref; -}; - -/// External interface to cleanup a mock server. This function will try terminate the mock server -/// with the given port number and cleanup any memory allocated for it. Returns true, unless a -/// mock server with the given port number does not exist, or the function panics. -/// -/// **NOTE:** Although `close()` on the listener for the mock server is called, this does not -/// currently work and the listener will continue handling requests. In this -/// case, it will always return a 404 once the mock server has been cleaned up. -bool pactffi_cleanup_mock_server(int mock_server_port); - -/// External interface to create a mock server. A pointer to the pact JSON as a C string is passed in, -/// as well as the port for the mock server to run on. A value of 0 for the port will result in a -/// port being allocated by the operating system. The port of the mock server is returned. -/// -/// # Errors -/// -/// Errors are returned as negative values. -/// -/// | Error | Description | -/// |-------|-------------| -/// | -1 | A null pointer was received | -/// | -2 | The pact JSON could not be parsed | -/// | -3 | The mock server could not be started | -/// | -4 | The method panicked | -/// | -5 | The address is not valid | -/// -int pactffi_create_mock_server(const char *pact_str, const char *addr_str, bool tls); - -/// As above, but creates it for a PactHandle -int pactffi_create_mock_server_for_pact(PactHandle pact, const char *addr_str, bool tls); - -void pactffi_with_specification(PactHandle pact, int specification_version); - -/// Adds a provider state to the Interaction -bool pactffi_given(InteractionHandle interaction, const char *description); - -/// Adds a provider state with params to the Interaction -bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value); - -/// Get self signed certificate for TLS mode -char* pactffi_get_tls_ca_certificate(); - -/// Free a string allocated on the Rust heap -void pactffi_free_string(const char *s); - -/// External interface to check if a mock server has matched all its requests. The port number is -/// passed in, and if all requests have been matched, true is returned. False is returned if there -/// is no mock server on the given port, or if any request has not been successfully matched, or -/// the method panics. -bool pactffi_mock_server_matched(int mock_server_port); - -/// External interface to get all the mismatches from a mock server. The port number of the mock -/// server is passed in, and a pointer to a C string with the mismatches in JSON format is -/// returned. -/// -/// **NOTE:** The JSON string for the result is allocated on the heap, and will have to be freed -/// once the code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is -/// provided for this purpose. -/// -/// # Errors -/// -/// If there is no mock server with the provided port number, or the function panics, a NULL -/// pointer will be returned. Don't try to dereference it, it will not end well for you. -/// -char* pactffi_mock_server_mismatches(int mock_server_port); - -/// Creates a new Interaction and returns a handle to it -InteractionHandle pactffi_new_interaction(PactHandle pact, const char *description); - -/// Creates a new Pact model and returns a handle to it -PactHandle pactffi_new_pact(const char *consumer_name, const char *provider_name); - -/// Sets the description for the Interaction -void pactffi_upon_receiving(InteractionHandle interaction, const char *description); - -/// Sets the description for the Interaction -void pactffi_with_request(InteractionHandle interaction, const char *method, const char *path); - -/// Sets header expectations -/// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_header.html -void pactffi_with_header_v2(InteractionHandle interaction, int interaction_part, const char *name, int index, const char *value); - -/// Sets query string expectation -/// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_query_parameter.html -void pactffi_with_query_parameter_v2(InteractionHandle interaction, const char *name, int index, const char *value); - -/// Sets the description for the Interaction -// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_body.html -bool pactffi_with_body(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body); - -// bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const uint8_t *body, size_t size); -bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, int size); - -int pactffi_with_multipart_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, const char *part_name); - -// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.response_status.html -void pactffi_response_status(InteractionHandle interaction, int status); - -/// External interface to trigger a mock server to write out its pact file. This function should -/// be called if all the consumer tests have passed. The directory to write the file to is passed -/// as the second parameter. If a NULL pointer is passed, the current working directory is used. -/// -/// Returns 0 if the pact file was successfully written. Returns a positive code if the file can -/// not be written, or there is no mock server running on that port or the function panics. -/// -/// # Errors -/// -/// Errors are returned as positive values. -/// -/// | Error | Description | -/// |-------|-------------| -/// | 1 | A general panic was caught | -/// | 2 | The pact file was not able to be written | -/// | 3 | A mock server with the provided port was not found | -int pactffi_write_pact_file(int mock_server_port, const char *directory, bool overwrite); - -void pactffi_with_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value); - -// Additional global logging functions -//void pactffi_log_message(const char *source, const char *log_level, const char *message); -//int pactffi_log_to_buffer(int level); -int pactffi_log_to_stdout(int level); -int pactffi_log_to_file(const char *file_name, int level_filter); -//char* pactffi_fetch_log_buffer(); - -int pactffi_using_plugin(PactHandle pact, const char *plugin_name, const char *plugin_version); -void pactffi_cleanup_plugins(PactHandle pact); -int pactffi_interaction_contents(InteractionHandle interaction, int interaction_part, const char *content_type, const char *contents); - -// Create a mock server for the provided Pact handle and transport. -int pactffi_create_mock_server_for_transport(PactHandle pact, const char *addr, int port, const char *transport, const char *transport_config); - +#include "pact.h" */ import "C" @@ -300,12 +142,12 @@ func (m *MockServer) CreateMockServer(pact string, address string, tls bool) (in cAddress := C.CString(address) defer free(cPact) defer free(cAddress) - tlsEnabled := 0 + tlsEnabled := false if tls { - tlsEnabled = 1 + tlsEnabled = true } - p := C.pactffi_create_mock_server(cPact, cAddress, C.int(tlsEnabled)) + p := C.pactffi_create_mock_server(cPact, cAddress, C.bool(tlsEnabled)) // | Error | Description | // |-------|-------------| @@ -378,7 +220,7 @@ func (m *MockServer) CleanupMockServer(port int) bool { log.Println("[DEBUG] mock server cleaning up port:", port) res := C.pactffi_cleanup_mock_server(C.int(port)) - return int(res) == 1 + return bool(res) } // WritePactFile writes the Pact to file. @@ -394,7 +236,7 @@ func (m *MockServer) WritePactFile(port int, dir string) error { // } // res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact))) - res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(0))) + res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.bool(false))) // | Error | Description | // |-------|-------------| @@ -448,12 +290,12 @@ func (m *MockServer) Start(address string, tls bool) (int, error) { log.Println("[DEBUG] mock server starting on address:", address) cAddress := C.CString(address) defer free(cAddress) - tlsEnabled := 0 + tlsEnabled := false if tls { - tlsEnabled = 1 + tlsEnabled = true } - p := C.pactffi_create_mock_server_for_pact(m.pact.handle, cAddress, C.int(tlsEnabled)) + p := C.pactffi_create_mock_server_for_pact(m.pact.handle, cAddress, C.bool(tlsEnabled)) // | Error | Description | // |-------|-------------| @@ -504,7 +346,7 @@ func (m *MockServer) StartTransport(transport string, address string, port int, cConfig := C.CString(configJson) defer free(cConfig) - p := C.pactffi_create_mock_server_for_transport(m.pact.handle, cAddress, C.int(port), cTransport, cConfig) + p := C.pactffi_create_mock_server_for_transport(m.pact.handle, cAddress, C.ushort(port), cTransport, cConfig) // | Error | Description // |-------|------------- @@ -555,8 +397,8 @@ func (m *MockServer) UsingPlugin(pluginName string, pluginVersion string) error cPluginVersion := C.CString(pluginVersion) defer free(cPluginVersion) - InstallSignalHandlers() r := C.pactffi_using_plugin(m.pact.handle, cPluginName, cPluginVersion) + InstallSignalHandlers() // 1 - A general panic was caught. // 2 - Failed to load the plugin. @@ -702,7 +544,7 @@ func (i *Interaction) withHeaders(part interactionPart, valueOrMatcher map[strin cValue := C.CString(value) defer free(cValue) - C.pactffi_with_header_v2(i.handle, C.int(part), cName, C.int(0), cValue) + C.pactffi_with_header_v2(i.handle, C.int(part), cName, C.ulong(0), cValue) } } @@ -721,7 +563,7 @@ func (i *Interaction) WithQuery(valueOrMatcher map[string][]interface{}) *Intera cValue := C.CString(value) defer free(cValue) - C.pactffi_with_query_parameter_v2(i.handle, cName, C.int(idx), cValue) + C.pactffi_with_query_parameter_v2(i.handle, cName, C.ulong(idx), cValue) } } @@ -773,7 +615,7 @@ func (i *Interaction) withBinaryBody(contentType string, body []byte, part inter cHeader := C.CString(contentType) defer free(cHeader) - C.pactffi_with_binary_file(i.handle, C.int(part), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + C.pactffi_with_binary_file(i.handle, C.int(part), cHeader, (*C.uchar)(unsafe.Pointer(&body[0])), C.ulong(len(body))) return i } @@ -811,7 +653,7 @@ func (i *Interaction) withMultipartFile(contentType string, filename string, mim // Set the expected HTTTP response status func (i *Interaction) WithStatus(status int) *Interaction { - C.pactffi_response_status(i.handle, C.int(status)) + C.pactffi_response_status(i.handle, C.ushort(status)) return i } diff --git a/internal/native/pact.h b/internal/native/pact.h index 519603f6f..c5865d040 100644 --- a/internal/native/pact.h +++ b/internal/native/pact.h @@ -7,7 +7,7 @@ #ifndef pact_ffi_h #define pact_ffi_h -/* Generated with cbindgen:0.24.3 */ +/* Generated with cbindgen:0.26.0 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ @@ -16,6 +16,70 @@ #include #include +/** + * The type of value detected after parsing the expression + */ +typedef enum ExpressionValueType { + /** + * If the type is unknown + */ + ExpressionValueType_Unknown, + /** + * String type + */ + ExpressionValueType_String, + /** + * Numeric type + */ + ExpressionValueType_Number, + /** + * Integer numeric type (no significant figures after the decimal point) + */ + ExpressionValueType_Integer, + /** + * Decimal numeric type (at least one significant figure after the decimal point) + */ + ExpressionValueType_Decimal, + /** + * Boolean type + */ + ExpressionValueType_Boolean, +} ExpressionValueType; + +/** + * Enum defining the categories that generators can be applied to + */ +typedef enum GeneratorCategory { + /** + * Request Method + */ + GeneratorCategory_METHOD, + /** + * Request Path + */ + GeneratorCategory_PATH, + /** + * Request/Response Header + */ + GeneratorCategory_HEADER, + /** + * Request Query Parameter + */ + GeneratorCategory_QUERY, + /** + * Body + */ + GeneratorCategory_BODY, + /** + * Response Status + */ + GeneratorCategory_STATUS, + /** + * Message metadata + */ + GeneratorCategory_METADATA, +} GeneratorCategory; + /** * Request or Response enum */ @@ -23,11 +87,11 @@ typedef enum InteractionPart { /** * Request part */ - InteractionPart_Request, + InteractionPart_Request = 0, /** * Response part */ - InteractionPart_Response, + InteractionPart_Response = 1, } InteractionPart; /** @@ -45,6 +109,44 @@ typedef enum LevelFilter { LevelFilter_Trace, } LevelFilter; +/** + * Enum defining the categories that matching rules can be applied to + */ +typedef enum MatchingRuleCategory { + /** + * Request Method + */ + MatchingRuleCategory_METHOD, + /** + * Request Path + */ + MatchingRuleCategory_PATH, + /** + * Request/Response Header + */ + MatchingRuleCategory_HEADER, + /** + * Request Query Parameter + */ + MatchingRuleCategory_QUERY, + /** + * Body + */ + MatchingRuleCategory_BODY, + /** + * Response Status + */ + MatchingRuleCategory_STATUS, + /** + * Message contents (body) + */ + MatchingRuleCategory_CONTENTS, + /** + * Message metadata + */ + MatchingRuleCategory_METADATA, +} MatchingRuleCategory; + /** * Enum defining the pact specification versions supported by the library */ @@ -75,16 +177,100 @@ typedef enum PactSpecification { PactSpecification_V4, } PactSpecification; +/** + * Asynchronous interactions as a sequence of messages + */ +typedef struct AsynchronousMessage AsynchronousMessage; + /** * Struct that defines the consumer of the pact. */ typedef struct Consumer Consumer; +/** + * Trait to represent a generator + */ +typedef struct Generator Generator; + +/** + * An iterator that enables FFI iteration over the generators for a particular generator + * category. + */ +typedef struct GeneratorCategoryIterator GeneratorCategoryIterator; + +/** + * Struct that defines the HTTP request. + */ +typedef struct HttpRequest HttpRequest; + +/** + * Struct that defines the HTTP response. + */ +typedef struct HttpResponse HttpResponse; + +/** + * Set of all matching rules + */ +typedef struct MatchingRule MatchingRule; + +/** + * An iterator that enables FFI iteration over the matching rules for a particular matching rule + * category. + */ +typedef struct MatchingRuleCategoryIterator MatchingRuleCategoryIterator; + +/** + * Result of parsing a matching rule definition + */ +typedef struct MatchingRuleDefinitionResult MatchingRuleDefinitionResult; + +/** + * An iterator over the matching rules from a matching definition expression. + */ +typedef struct MatchingRuleIterator MatchingRuleIterator; + +/** + * The matching rule or reference from parsing the matching definition expression. + * + * For matching rules, the ID corresponds to the following rules: + * | Rule | ID | + * | ---- | -- | + * | Equality | 1 | + * | Regex | 2 | + * | Type | 3 | + * | MinType | 4 | + * | MaxType | 5 | + * | MinMaxType | 6 | + * | Timestamp | 7 | + * | Time | 8 | + * | Date | 9 | + * | Include | 10 | + * | Number | 11 | + * | Integer | 12 | + * | Decimal | 13 | + * | Null | 14 | + * | ContentType | 15 | + * | ArrayContains | 16 | + * | Values | 17 | + * | Boolean | 18 | + * | StatusCode | 19 | + * | NotEmpty | 20 | + * | Semver | 21 | + * | EachKey | 22 | + * | EachValue | 23 | + */ +typedef struct MatchingRuleResult MatchingRuleResult; + /** * Struct that defines a message. */ typedef struct Message Message; +/** + * Contents of a message interaction + */ +typedef struct MessageContents MessageContents; + /** * An iterator that enables FFI iteration over metadata by putting all the keys on the heap * and tracking which one we're currently at. @@ -128,18 +314,38 @@ typedef struct Mismatches Mismatches; */ typedef struct MismatchesIterator MismatchesIterator; +/** + * Opaque type for use as a pointer to a Pact model + */ +typedef struct Pact Pact; + +/** + * An iterator over asynchronous messages in a V4 pact. + */ +typedef struct PactAsyncMessageIterator PactAsyncMessageIterator; + +/** + * Opaque type for use as a pointer to a Pact interaction model + */ +typedef struct PactInteraction PactInteraction; + +/** + * An iterator over the interactions in a pact. + */ +typedef struct PactInteractionIterator PactInteractionIterator; + /** * An iterator over messages in a pact. */ typedef struct PactMessageIterator PactMessageIterator; /** - * An iterator over synchronous HTTP request/response interactions in a pact. + * An iterator over synchronous HTTP request/response interactions in a V4 pact. */ typedef struct PactSyncHttpIterator PactSyncHttpIterator; /** - * An iterator over synchronous request/response messages in a pact. + * An iterator over synchronous request/response messages in a V4 pact. */ typedef struct PactSyncMessageIterator PactSyncMessageIterator; @@ -181,6 +387,34 @@ typedef struct SynchronousMessage SynchronousMessage; */ typedef struct VerifierHandle VerifierHandle; +/** + * A single key-value pair of a path and generator exported to the C-side. + */ +typedef struct GeneratorKeyValuePair { + /** + * The generator path + */ + const char *path; + /** + * The generator + */ + const struct Generator *generator; +} GeneratorKeyValuePair; + +/** + * A single key-value pair of a path and matching rule exported to the C-side. + */ +typedef struct MatchingRuleKeyValuePair { + /** + * The matching rule path + */ + const char *path; + /** + * The matching rule + */ + const struct MatchingRule *rule; +} MatchingRuleKeyValuePair; + /** * A single key-value pair exported to the C-side. */ @@ -293,6 +527,8 @@ void pactffi_init(const char *log_env_var); * Initialises logging, and sets the log level explicitly. This function should only be called * once, as it tries to install a global tracing subscriber. * + * * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR, NONE/OFF. Case-insensitive. Defaults to INFO. + * * # Safety * * Exported functions are inherently unsafe. @@ -315,13 +551,15 @@ void pactffi_enable_ansi_support(void); * * * `source` - String. The source of the log, such as the class or caller framework to * disambiguate log lines from the rust logging (e.g. pact_go) - * * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR + * * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR. Case-insensitive. Defaults to INFO. * * `message` - Message to log * * # Safety * This function will fail if any of the pointers passed to it are invalid. */ -void pactffi_log_message(const char *source, const char *log_level, const char *message); +void pactffi_log_message(const char *source, + const char *log_level, + const char *message); /** * Match a pair of messages, producing a collection of mismatches, @@ -420,12 +658,12 @@ int pactffi_get_error_message(char *buffer, /** * Convenience function to direct all logging to stdout. */ -int pactffi_log_to_stdout(enum LevelFilter level_filter); +int pactffi_log_to_stdout(int level_filter); /** * Convenience function to direct all logging to stderr. */ -int pactffi_log_to_stderr(enum LevelFilter level_filter); +int pactffi_log_to_stderr(int level_filter); /** * Convenience function to direct all logging to a file. @@ -434,12 +672,12 @@ int pactffi_log_to_stderr(enum LevelFilter level_filter); * This function will fail if the file_name pointer is invalid or does not point to a NULL * terminated string. */ -int pactffi_log_to_file(const char *file_name, enum LevelFilter level_filter); +int pactffi_log_to_file(const char *file_name, int level_filter); /** * Convenience function to direct all logging to a task local memory buffer. */ -int pactffi_log_to_buffer(enum LevelFilter level_filter); +int pactffi_log_to_buffer(int level_filter); /** * Initialize the FFI logger with no sinks. @@ -494,7 +732,7 @@ void pactffi_logger_init(void); * undefined behaviour. */ int pactffi_logger_attach_sink(const char *sink_specifier, - enum LevelFilter level_filter); + int level_filter); /** * Apply the previously configured sinks and levels to the program. If no sinks have been setup, @@ -524,42 +762,43 @@ int pactffi_logger_apply(void); const char *pactffi_fetch_log_buffer(const char *log_id); /** - * Get a copy of this consumer's name. - * - * The copy must be deleted with `pactffi_string_delete`. - * - * # Usage - * - * ```c - * // Assuming `file_name` and `json_str` are already defined. - * - * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str); - * if (message_pact == NULLPTR) { - * // handle error. - * } - * - * Consumer *consumer = pactffi_message_pact_get_consumer(message_pact); - * if (consumer == NULLPTR) { - * // handle error. - * } + * Parses the provided JSON into a Pact model. The returned Pact model must be freed with the + * `pactffi_pact_model_delete` function when no longer needed. * - * char *name = pactffi_consumer_get_name(consumer); - * if (name == NULL) { - * // handle error. - * } + * # Error Handling * - * printf("%s\n", name); + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +struct Pact *pactffi_parse_pact_json(const char *json); + +/** + * Frees the memory used by the Pact model + */ +void pactffi_pact_model_delete(struct Pact *pact); + +/** + * Returns an iterator over all the interactions in the Pact. The iterator will have to be + * deleted using the `pactffi_pact_interaction_iter_delete` function. The iterator will + * contain a copy of the interactions, so it will not be affected but mutations to the Pact + * model and will still function if the Pact model is deleted. * - * pactffi_string_delete(name); - * ``` + * # Safety + * This function is safe as long as the Pact pointer is a valid pointer. * * # Errors - * - * This function will fail if it is passed a NULL pointer, - * or the Rust string contains an embedded NULL byte. - * In the case of error, a NULL pointer will be returned. + * On any error, this function will return a NULL pointer. */ -const char *pactffi_consumer_get_name(const struct Consumer *consumer); +struct PactInteractionIterator *pactffi_pact_model_interaction_iterator(struct Pact *pact); + +/** + * Returns the Pact specification enum that the Pact is for. + */ +int pactffi_pact_spec_version(const struct Pact *pact); + +/** + * Frees the memory used by the Pact interaction model + */ +void pactffi_pact_interaction_delete(const struct PactInteraction *interaction); /** * Get a mutable pointer to a newly-created default message on the heap. @@ -572,43 +811,49 @@ const char *pactffi_consumer_get_name(const struct Consumer *consumer); * * Returns NULL on error. */ -struct Message *pactffi_message_new(void); +struct AsynchronousMessage *pactffi_async_message_new(void); /** - * Constructs a `Message` from the JSON string + * Destroy the `AsynchronousMessage` being pointed to. + */ +void pactffi_async_message_delete(const struct AsynchronousMessage *message); + +/** + * Get the message contents of an `AsynchronousMessage` as a `MessageContents` pointer. * * # Safety * - * This function is safe. + * The data pointed to by the pointer this function returns will be deleted when the message + * is deleted. Trying to use if after the message is deleted will result in undefined behaviour. * * # Error Handling * - * If the JSON string is invalid or not UTF-8 encoded, returns a NULL. + * If the message is NULL, returns NULL. */ -struct Message *pactffi_message_new_from_json(unsigned int index, - const char *json_str, - enum PactSpecification spec_version); +const struct MessageContents *pactffi_async_message_get_contents(const struct AsynchronousMessage *message); /** - * Constructs a `Message` from a body with a given content-type. + * Generate the message contents of an `AsynchronousMessage` as a + * `MessageContents` pointer. + * + * This function differs from [`pactffi_async_message_get_contents`] in + * that it will process the message contents for any generators or matchers + * that are present in the message in order to generate the actual message + * contents as would be received by the consumer. * * # Safety * - * This function is safe. + * The data pointed to by the pointer must be deleted with + * [`pactffi_message_contents_delete`][crate::models::contents::pactffi_message_contents_delete] * * # Error Handling * - * If the body or content type are invalid or not UTF-8 encoded, returns NULL. - */ -struct Message *pactffi_message_new_from_body(const char *body, const char *content_type); - -/** - * Destroy the `Message` being pointed to. + * If the message is NULL, returns NULL. */ -void pactffi_message_delete(struct Message *message); +const struct MessageContents *pactffi_async_message_generate_contents(const struct AsynchronousMessage *message); /** - * Get the contents of a `Message` in string form. + * Get the message contents of an `AsynchronousMessage` in string form. * * # Safety * @@ -623,10 +868,14 @@ void pactffi_message_delete(struct Message *message); * no mechanism to differentiate with this function call alone between * a NULL message and a missing message body. */ -const char *pactffi_message_get_contents(const struct Message *message); +const char *pactffi_async_message_get_contents_str(const struct AsynchronousMessage *message); /** - * Sets the contents of the message. + * Sets the contents of the message as a string. + * + * * `message` - the message to set the contents for + * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. + * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * @@ -638,12 +887,12 @@ const char *pactffi_message_get_contents(const struct Message *message); * If the contents is a NULL pointer, it will set the message contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_message_set_contents(struct Message *message, - const char *contents, - const char *content_type); +void pactffi_async_message_set_contents_str(struct AsynchronousMessage *message, + const char *contents, + const char *content_type); /** - * Get the length of the contents of a `Message`. + * Get the length of the contents of a `AsynchronousMessage`. * * # Safety * @@ -651,17 +900,17 @@ void pactffi_message_set_contents(struct Message *message, * * # Error Handling * - * If the message is NULL, returns 0. If the body of the message + * If the message is NULL, returns 0. If the body of the request * is missing, then this function also returns 0. */ -size_t pactffi_message_get_contents_length(const struct Message *message); +size_t pactffi_async_message_get_contents_length(const struct AsynchronousMessage *message); /** - * Get the contents of a `Message` as a pointer to an array of bytes. + * Get the contents of an `AsynchronousMessage` as a pointer to an array of bytes. * * # Safety * - * The number of bytes in the buffer will be returned by `pactffi_message_get_contents_length`. + * The number of bytes in the buffer will be returned by `pactffi_async_message_get_contents_length`. * It is safe to use the pointer while the message is not deleted or changed. Using the pointer * after the message is mutated or deleted may lead to undefined behaviour. * @@ -670,11 +919,16 @@ size_t pactffi_message_get_contents_length(const struct Message *message); * If the message is NULL, returns NULL. If the body of the message * is missing, then this function also returns NULL. */ -const unsigned char *pactffi_message_get_contents_bin(const struct Message *message); +const unsigned char *pactffi_async_message_get_contents_bin(const struct AsynchronousMessage *message); /** * Sets the contents of the message as an array of bytes. * + * * `message` - the message to set the contents for + * * `contents` - pointer to contents to copy from + * * `len` - number of bytes to copy from the contents pointer + * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. + * * # Safety * * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned @@ -685,10 +939,10 @@ const unsigned char *pactffi_message_get_contents_bin(const struct Message *mess * If the contents is a NULL pointer, it will set the message contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_message_set_contents_bin(struct Message *message, - const unsigned char *contents, - size_t len, - const char *content_type); +void pactffi_async_message_set_contents_bin(struct AsynchronousMessage *message, + const unsigned char *contents, + size_t len, + const char *content_type); /** * Get a copy of the description. @@ -697,8 +951,7 @@ void pactffi_message_set_contents_bin(struct Message *message, * * The returned string must be deleted with `pactffi_string_delete`. * - * Since it is a copy, the returned string may safely outlive - * the `Message`. + * Since it is a copy, the returned string may safely outlive the `AsynchronousMessage`. * * # Errors * @@ -707,10 +960,10 @@ void pactffi_message_set_contents_bin(struct Message *message, * This function may fail if the Rust string contains embedded * null ('\0') bytes. */ -const char *pactffi_message_get_description(const struct Message *message); +const char *pactffi_async_message_get_description(const struct AsynchronousMessage *message); /** - * Write the `description` field on the `Message`. + * Write the `description` field on the `AsynchronousMessage`. * * # Safety * @@ -724,7 +977,8 @@ const char *pactffi_message_get_description(const struct Message *message); * * Errors will be reported with a non-zero return value. */ -int pactffi_message_set_description(struct Message *message, const char *description); +int pactffi_async_message_set_description(struct AsynchronousMessage *message, + const char *description); /** * Get a copy of the provider state at the given index from this message. @@ -733,8 +987,7 @@ int pactffi_message_set_description(struct Message *message, const char *descrip * * The returned structure must be deleted with `provider_state_delete`. * - * Since it is a copy, the returned structure may safely outlive - * the `Message`. + * Since it is a copy, the returned structure may safely outlive the `AsynchronousMessage`. * * # Error Handling * @@ -743,8 +996,8 @@ int pactffi_message_set_description(struct Message *message, const char *descrip * This function may fail if the index requested is out of bounds, * or if any of the Rust strings contain embedded null ('\0') bytes. */ -const struct ProviderState *pactffi_message_get_provider_state(const struct Message *message, - unsigned int index); +const struct ProviderState *pactffi_async_message_get_provider_state(const struct AsynchronousMessage *message, + unsigned int index); /** * Get an iterator over provider states. @@ -757,381 +1010,399 @@ const struct ProviderState *pactffi_message_get_provider_state(const struct Mess * * Returns NULL if an error occurs. */ -struct ProviderStateIterator *pactffi_message_get_provider_state_iter(struct Message *message); +struct ProviderStateIterator *pactffi_async_message_get_provider_state_iter(struct AsynchronousMessage *message); /** - * Get the next value from the iterator. + * Get a copy of this consumer's name. * - * # Safety + * The copy must be deleted with `pactffi_string_delete`. * - * The underlying data must not change during iteration. + * # Usage * - * If a previous call panicked, then the internal mutex will have been poisoned and this - * function will return NULL. + * ```c + * // Assuming `file_name` and `json_str` are already defined. * - * # Error Handling + * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str); + * if (message_pact == NULLPTR) { + * // handle error. + * } * - * Returns NULL if an error occurs. - */ -struct ProviderState *pactffi_provider_state_iter_next(struct ProviderStateIterator *iter); - -/** - * Delete the iterator. - */ -void pactffi_provider_state_iter_delete(struct ProviderStateIterator *iter); - -/** - * Get a copy of the metadata value indexed by `key`. + * Consumer *consumer = pactffi_message_pact_get_consumer(message_pact); + * if (consumer == NULLPTR) { + * // handle error. + * } * - * # Safety + * char *name = pactffi_consumer_get_name(consumer); + * if (name == NULL) { + * // handle error. + * } * - * The returned string must be deleted with `pactffi_string_delete`. + * printf("%s\n", name); * - * Since it is a copy, the returned string may safely outlive - * the `Message`. + * pactffi_string_delete(name); + * ``` * - * The returned pointer will be NULL if the metadata does not contain - * the given key, or if an error occurred. + * # Errors * - * # Error Handling + * This function will fail if it is passed a NULL pointer, + * or the Rust string contains an embedded NULL byte. + * In the case of error, a NULL pointer will be returned. + */ +const char *pactffi_consumer_get_name(const struct Consumer *consumer); + +/** + * Get the consumer from a Pact. This returns a copy of the consumer model, and needs to + * be cleaned up with `pactffi_pact_consumer_delete` when no longer required. * - * On failure, this function will return a NULL pointer. + * # Errors * - * This function may fail if the provided `key` string contains - * invalid UTF-8, or if the Rust string contains embedded null ('\0') - * bytes. + * This function will fail if it is passed a NULL pointer. + * In the case of error, a NULL pointer will be returned. */ -const char *pactffi_message_find_metadata(const struct Message *message, const char *key); +const struct Consumer *pactffi_pact_get_consumer(const struct Pact *pact); /** - * Insert the (`key`, `value`) pair into this Message's - * `metadata` HashMap. + * Frees the memory used by the Pact consumer + */ +void pactffi_pact_consumer_delete(const struct Consumer *consumer); + +/** + * Delete the message contents instance. * * # Safety * - * This function returns an enum indicating the result; - * see the comments on HashMapInsertStatus for details. - * - * # Error Handling + * This should only be called on a message contents that require deletion. + * The function creating the message contents should document whether it + * requires deletion. * - * This function may fail if the provided `key` or `value` strings - * contain invalid UTF-8. + * Deleting a message content which is associated with an interaction + * will result in undefined behaviour. */ -int pactffi_message_insert_metadata(struct Message *message, const char *key, const char *value); +void pactffi_message_contents_delete(const struct MessageContents *contents); /** - * Get an iterator over the metadata of a message. + * Get the message contents in string form. * * # Safety * - * This iterator carries a pointer to the message, and must - * not outlive the message. + * The returned string must be deleted with `pactffi_string_delete`. * - * The message metadata also must not be modified during iteration. If it is, - * the old iterator must be deleted and a new iterator created. + * The returned string can outlive the message. * * # Error Handling * - * On failure, this function will return a NULL pointer. - * - * This function may fail if any of the Rust strings contain - * embedded null ('\0') bytes. + * If the message contents is NULL, returns NULL. If the body of the message + * is missing, then this function also returns NULL. This means there's + * no mechanism to differentiate with this function call alone between + * a NULL message and a missing message body. */ -struct MessageMetadataIterator *pactffi_message_get_metadata_iter(struct Message *message); +const char *pactffi_message_contents_get_contents_str(const struct MessageContents *contents); /** - * Get the next key and value out of the iterator, if possible + * Sets the contents of the message as a string. + * + * * `contents` - the message contents to set the contents for + * * `contents_str` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. + * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * The underlying data must not change during iteration. + * The message contents and content type must either be NULL pointers, or point to valid + * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. * * # Error Handling * - * If no further data is present, returns NULL. - */ -struct MessageMetadataPair *pactffi_message_metadata_iter_next(struct MessageMetadataIterator *iter); - -/** - * Free the metadata iterator when you're done using it. - */ -void pactffi_message_metadata_iter_delete(struct MessageMetadataIterator *iter); - -/** - * Free a pair of key and value returned from `message_metadata_iter_next`. + * If the contents string is a NULL pointer, it will set the message contents as null. If the content + * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_message_metadata_pair_delete(struct MessageMetadataPair *pair); +void pactffi_message_contents_set_contents_str(struct MessageContents *contents, + const char *contents_str, + const char *content_type); /** - * Construct a new `MessagePact` from the JSON string. - * The provided file name is used when generating error messages. + * Get the length of the message contents. * * # Safety * - * The `file_name` and `json_str` parameters must both be valid UTF-8 - * encoded strings. + * This function is safe. * * # Error Handling * - * On error, this function will return a null pointer. - */ -struct MessagePact *pactffi_message_pact_new_from_json(const char *file_name, const char *json_str); - -/** - * Delete the `MessagePact` being pointed to. + * If the message is NULL, returns 0. If the body of the message + * is missing, then this function also returns 0. */ -void pactffi_message_pact_delete(struct MessagePact *message_pact); +size_t pactffi_message_contents_get_contents_length(const struct MessageContents *contents); /** - * Get a pointer to the Consumer struct inside the MessagePact. - * This is a mutable borrow: The caller may mutate the Consumer - * through this pointer. + * Get the contents of a message as a pointer to an array of bytes. * * # Safety * - * This function is safe. + * The number of bytes in the buffer will be returned by `pactffi_message_contents_get_contents_length`. + * It is safe to use the pointer while the message is not deleted or changed. Using the pointer + * after the message is mutated or deleted may lead to undefined behaviour. * * # Error Handling * - * This function will only fail if it is passed a NULL pointer. - * In the case of error, a NULL pointer will be returned. + * If the message is NULL, returns NULL. If the body of the message + * is missing, then this function also returns NULL. */ -struct Consumer *pactffi_message_pact_get_consumer(struct MessagePact *message_pact); +const unsigned char *pactffi_message_contents_get_contents_bin(const struct MessageContents *contents); /** - * Get a pointer to the Provider struct inside the MessagePact. - * This is a mutable borrow: The caller may mutate the Provider - * through this pointer. + * Sets the contents of the message as an array of bytes. + * + * * `message` - the message contents to set the contents for + * * `contents_bin` - pointer to contents to copy from + * * `len` - number of bytes to copy from the contents pointer + * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * This function is safe. + * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned + * and consecutive. Otherwise behaviour is undefined. * * # Error Handling * - * This function will only fail if it is passed a NULL pointer. - * In the case of error, a NULL pointer will be returned. + * If the contents is a NULL pointer, it will set the message contents as null. If the content + * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -struct Provider *pactffi_message_pact_get_provider(struct MessagePact *message_pact); +void pactffi_message_contents_set_contents_bin(struct MessageContents *contents, + const unsigned char *contents_bin, + size_t len, + const char *content_type); /** - * Get an iterator over the messages of a message pact. + * Get an iterator over the metadata of a message. + * + * The returned pointer must be deleted with `pactffi_message_metadata_iter_delete` when done + * with it. * * # Safety * - * This iterator carries a pointer to the message pact, and must - * not outlive the message pact. + * This iterator carries a pointer to the message contents, and must + * not outlive the message. * - * The message pact messages also must not be modified during iteration. - * If they are, the old iterator must be deleted and a new iterator created. + * The message metadata also must not be modified during iteration. If it is, + * the old iterator must be deleted and a new iterator created. * * # Error Handling * * On failure, this function will return a NULL pointer. * - * This function may fail if any of the Rust strings contain embedded - * null ('\0') bytes. + * This function may fail if any of the Rust strings contain + * embedded null ('\0') bytes. */ -struct MessagePactMessageIterator *pactffi_message_pact_get_message_iter(struct MessagePact *message_pact); +struct MessageMetadataIterator *pactffi_message_contents_get_metadata_iter(const struct MessageContents *contents); /** - * Get the next message from the message pact. + * Get an iterator over the matching rules for a category of a message. + * + * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done + * with it. + * + * Note that there could be multiple matching rules for the same key, so this iterator will + * sequentially return each rule with the same key. + * + * For sample, given the following rules: + * "$.a" => Type, + * "$.b" => Regex("\\d+"), Number + * + * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number) * * # Safety * - * This function is safe. + * The iterator contains a copy of the data, so is safe to use when the message or message + * contents has been deleted. * * # Error Handling * - * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. - */ -struct Message *pactffi_message_pact_message_iter_next(struct MessagePactMessageIterator *iter); - -/** - * Delete the iterator. + * On failure, this function will return a NULL pointer. */ -void pactffi_message_pact_message_iter_delete(struct MessagePactMessageIterator *iter); +struct MatchingRuleCategoryIterator *pactffi_message_contents_get_matching_rule_iter(const struct MessageContents *contents, + enum MatchingRuleCategory category); /** - * Get a copy of the metadata value indexed by `key1` and `key2`. + * Get an iterator over the matching rules for a category of an HTTP request. * - * # Safety + * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done + * with it. * - * Since it is a copy, the returned string may safely outlive - * the `Message`. + * For sample, given the following rules: + * "$.a" => Type, + * "$.b" => Regex("\\d+"), Number * - * The returned string must be deleted with `pactffi_string_delete`. + * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number) * - * The returned pointer will be NULL if the metadata does not contain - * the given key, or if an error occurred. + * # Safety + * + * The iterator contains a copy of the data, so is safe to use when the interaction or request + * contents has been deleted. * * # Error Handling * * On failure, this function will return a NULL pointer. - * - * This function may fail if the provided `key1` or `key2` strings contains - * invalid UTF-8, or if the Rust string contains embedded null ('\0') - * bytes. */ -const char *pactffi_message_pact_find_metadata(const struct MessagePact *message_pact, - const char *key1, - const char *key2); +struct MatchingRuleCategoryIterator *pactffi_request_contents_get_matching_rule_iter(const struct HttpRequest *request, + enum MatchingRuleCategory category); /** - * Get an iterator over the metadata of a message pact. + * Get an iterator over the matching rules for a category of an HTTP response. * - * # Safety + * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done + * with it. * - * This iterator carries a pointer to the message pact, and must - * not outlive the message pact. + * For sample, given the following rules: + * "$.a" => Type, + * "$.b" => Regex("\\d+"), Number * - * The message pact metadata also must not be modified during iteration. If it is, - * the old iterator must be deleted and a new iterator created. + * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number) + * + * # Safety + * + * The iterator contains a copy of the data, so is safe to use when the interaction or response + * contents has been deleted. * * # Error Handling * * On failure, this function will return a NULL pointer. - * - * This function may fail if any of the Rust strings contain - * embedded null ('\0') bytes. */ -struct MessagePactMetadataIterator *pactffi_message_pact_get_metadata_iter(struct MessagePact *message_pact); +struct MatchingRuleCategoryIterator *pactffi_response_contents_get_matching_rule_iter(const struct HttpResponse *response, + enum MatchingRuleCategory category); /** - * Get the next triple out of the iterator, if possible + * Get an iterator over the generators for a category of a message. + * + * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done + * with it. * * # Safety * - * This operation is invalid if the underlying data has been changed during iteration. + * The iterator contains a copy of the data, so is safe to use when the message or message + * contents has been deleted. * * # Error Handling * - * Returns null if no next element is present. - */ -struct MessagePactMetadataTriple *pactffi_message_pact_metadata_iter_next(struct MessagePactMetadataIterator *iter); - -/** - * Free the metadata iterator when you're done using it. - */ -void pactffi_message_pact_metadata_iter_delete(struct MessagePactMetadataIterator *iter); - -/** - * Free a triple returned from `pactffi_message_pact_metadata_iter_next`. + * On failure, this function will return a NULL pointer. */ -void pactffi_message_pact_metadata_triple_delete(struct MessagePactMetadataTriple *triple); +struct GeneratorCategoryIterator *pactffi_message_contents_get_generators_iter(const struct MessageContents *contents, + enum GeneratorCategory category); /** - * Get a copy of this provider's name. - * - * The copy must be deleted with `pactffi_string_delete`. - * - * # Usage - * - * ```c - * // Assuming `file_name` and `json_str` are already defined. - * - * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str); - * if (message_pact == NULLPTR) { - * // handle error. - * } + * Get an iterator over the generators for a category of an HTTP request. * - * Provider *provider = pactffi_message_pact_get_provider(message_pact); - * if (provider == NULLPTR) { - * // handle error. - * } - * - * char *name = pactffi_provider_get_name(provider); - * if (name == NULL) { - * // handle error. - * } + * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done + * with it. * - * printf("%s\n", name); + * # Safety * - * pactffi_string_delete(name); - * ``` + * The iterator contains a copy of the data, so is safe to use when the interaction or request + * contents has been deleted. * - * # Errors + * # Error Handling * - * This function will fail if it is passed a NULL pointer, - * or the Rust string contains an embedded NULL byte. - * In the case of error, a NULL pointer will be returned. + * On failure, this function will return a NULL pointer. */ -const char *pactffi_provider_get_name(const struct Provider *provider); +struct GeneratorCategoryIterator *pactffi_request_contents_get_generators_iter(const struct HttpRequest *request, + enum GeneratorCategory category); /** - * Get the name of the provider state as a string, which needs to be deleted with `pactffi_string_delete`. + * Get an iterator over the generators for a category of an HTTP response. + * + * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done + * with it. * * # Safety * - * This function is safe. + * The iterator contains a copy of the data, so is safe to use when the interaction or response + * contents has been deleted. * * # Error Handling * - * If the provider_state param is NULL, this returns NULL. + * On failure, this function will return a NULL pointer. */ -const char *pactffi_provider_state_get_name(const struct ProviderState *provider_state); +struct GeneratorCategoryIterator *pactffi_response_contents_get_generators_iter(const struct HttpResponse *response, + enum GeneratorCategory category); /** - * Get an iterator over the params of a provider state. + * Parse a matcher definition string into a MatchingRuleDefinition containing the example value, + * and matching rules and any generator. * - * # Safety + * The following are examples of matching rule definitions: + * * `matching(type,'Name')` - type matcher with string value 'Name' + * * `matching(number,100)` - number matcher + * * `matching(datetime, 'yyyy-MM-dd','2000-01-01')` - datetime matcher with format string * - * This iterator carries a pointer to the provider state, and must - * not outlive the provider state. + * See [Matching Rule definition expressions](https://docs.rs/pact_models/latest/pact_models/matchingrules/expressions/index.html). * - * The provider state params also must not be modified during iteration. If it is, - * the old iterator must be deleted and a new iterator created. + * The returned value needs to be freed up with the `pactffi_matcher_definition_delete` function. * * # Errors + * If the expression is invalid, the MatchingRuleDefinition error will be set. You can check for + * this value with the `pactffi_matcher_definition_error` function. * - * On failure, this function will return a NULL pointer. + * # Safety * - * This function may fail if any of the Rust strings contain - * embedded null ('\0') bytes. + * This function is safe if the expression is a valid NULL terminated string pointer. */ -struct ProviderStateParamIterator *pactffi_provider_state_get_param_iter(struct ProviderState *provider_state); +const struct MatchingRuleDefinitionResult *pactffi_parse_matcher_definition(const char *expression); /** - * Get the next key and value out of the iterator, if possible - * - * Returns a pointer to a heap allocated array of 2 elements, the pointer to the - * key string on the heap, and the pointer to the value string on the heap. - * - * # Safety - * - * The underlying data must not be modified during iteration. - * - * The user needs to free both the contained strings and the array. - * - * # Error Handling + * Returns any error message from parsing a matching definition expression. If there is no error, + * it will return a NULL pointer, otherwise returns the error message as a NULL-terminated string. + * The returned string must be freed using the `pactffi_string_delete` function once done with it. + */ +const char *pactffi_matcher_definition_error(const struct MatchingRuleDefinitionResult *definition); + +/** + * Returns the value from parsing a matching definition expression. If there was an error, + * it will return a NULL pointer, otherwise returns the value as a NULL-terminated string. + * The returned string must be freed using the `pactffi_string_delete` function once done with it. * - * Returns NULL if there's no further elements or the iterator is NULL. + * Note that different expressions values can have types other than a string. Use + * `pactffi_matcher_definition_value_type` to get the actual type of the value. This function + * will always return the string representation of the value. */ -struct ProviderStateParamPair *pactffi_provider_state_param_iter_next(struct ProviderStateParamIterator *iter); +const char *pactffi_matcher_definition_value(const struct MatchingRuleDefinitionResult *definition); /** - * Free the provider state when you're done using it. + * Frees the memory used by the result of parsing the matching definition expression */ -void pactffi_provider_state_delete(struct ProviderState *provider_state); +void pactffi_matcher_definition_delete(const struct MatchingRuleDefinitionResult *definition); /** - * Free the provider state param iterator when you're done using it. + * Returns the generator from parsing a matching definition expression. If there was an error or + * there is no associated generator, it will return a NULL pointer, otherwise returns the generator + * as a pointer. + * + * The generator pointer will be a valid pointer as long as `pactffi_matcher_definition_delete` + * has not been called on the definition. Using the generator pointer after the definition + * has been deleted will result in undefined behaviour. */ -void pactffi_provider_state_param_iter_delete(struct ProviderStateParamIterator *iter); +const struct Generator *pactffi_matcher_definition_generator(const struct MatchingRuleDefinitionResult *definition); /** - * Free a pair of key and value returned from `pactffi_provider_state_param_iter_next`. + * Returns the type of the value from parsing a matching definition expression. If there was an + * error parsing the expression, it will return Unknown. */ -void pactffi_provider_state_param_pair_delete(struct ProviderStateParamPair *pair); +enum ExpressionValueType pactffi_matcher_definition_value_type(const struct MatchingRuleDefinitionResult *definition); /** * Free the iterator when you're done using it. */ -void pactffi_pact_message_iter_delete(struct PactMessageIterator *iter); +void pactffi_matching_rule_iter_delete(struct MatchingRuleIterator *iter); /** - * Get the next message from the message pact. As the messages returned are owned by the - * iterator, they do not need to be deleted but will be cleaned up when the iterator is + * Returns an iterator over the matching rules from the parsed definition. The iterator needs to + * be deleted with the `pactffi_matching_rule_iter_delete` function once done with it. + * + * If there was an error parsing the expression, this function will return a NULL pointer. + */ +struct MatchingRuleIterator *pactffi_matcher_definition_iter(const struct MatchingRuleDefinitionResult *definition); + +/** + * Get the next matching rule or reference from the iterator. As the values returned are owned + * by the iterator, they do not need to be deleted but will be cleaned up when the iterator is * deleted. * * Will return a NULL pointer when the iterator has advanced past the end of the list. @@ -1140,64 +1411,202 @@ void pactffi_pact_message_iter_delete(struct PactMessageIterator *iter); * * This function is safe. * - * Deleting a message returned by the iterator can lead to undefined behaviour. - * * # Error Handling * * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. */ -struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); +const struct MatchingRuleResult *pactffi_matching_rule_iter_next(struct MatchingRuleIterator *iter); + +/** + * Return the ID of the matching rule. + * + * The ID corresponds to the following rules: + * | Rule | ID | + * | ---- | -- | + * | Equality | 1 | + * | Regex | 2 | + * | Type | 3 | + * | MinType | 4 | + * | MaxType | 5 | + * | MinMaxType | 6 | + * | Timestamp | 7 | + * | Time | 8 | + * | Date | 9 | + * | Include | 10 | + * | Number | 11 | + * | Integer | 12 | + * | Decimal | 13 | + * | Null | 14 | + * | ContentType | 15 | + * | ArrayContains | 16 | + * | Values | 17 | + * | Boolean | 18 | + * | StatusCode | 19 | + * | NotEmpty | 20 | + * | Semver | 21 | + * | EachKey | 22 | + * | EachValue | 23 | + * + * # Safety + * + * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the + * iterator has not been deleted. + */ +uint16_t pactffi_matching_rule_id(const struct MatchingRuleResult *rule_result); + +/** + * Returns the associated value for the matching rule. If the matching rule does not have an + * associated value, will return a NULL pointer. + * + * The associated values for the rules are: + * | Rule | ID | VALUE | + * | ---- | -- | ----- | + * | Equality | 1 | NULL | + * | Regex | 2 | Regex value | + * | Type | 3 | NULL | + * | MinType | 4 | Minimum value | + * | MaxType | 5 | Maximum value | + * | MinMaxType | 6 | "min:max" | + * | Timestamp | 7 | Format string | + * | Time | 8 | Format string | + * | Date | 9 | Format string | + * | Include | 10 | String value | + * | Number | 11 | NULL | + * | Integer | 12 | NULL | + * | Decimal | 13 | NULL | + * | Null | 14 | NULL | + * | ContentType | 15 | Content type | + * | ArrayContains | 16 | NULL | + * | Values | 17 | NULL | + * | Boolean | 18 | NULL | + * | StatusCode | 19 | NULL | + * | NotEmpty | 20 | NULL | + * | Semver | 21 | NULL | + * | EachKey | 22 | NULL | + * | EachValue | 23 | NULL | + * + * Will return a NULL pointer if the matching rule was a reference or does not have an + * associated value. + * + * # Safety + * + * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the + * iterator it came from has not been deleted. + */ +const char *pactffi_matching_rule_value(const struct MatchingRuleResult *rule_result); /** - * Get the next synchronous request/response message from the pact. As the messages returned are owned by the - * iterator, they do not need to be deleted but will be cleaned up when the iterator is - * deleted. + * Returns the matching rule pointer for the matching rule. Will return a NULL pointer if the + * matching rule result was a reference. * - * Will return a NULL pointer when the iterator has advanced past the end of the list. + * # Safety + * + * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the + * iterator it came from has not been deleted. + */ +const struct MatchingRule *pactffi_matching_rule_pointer(const struct MatchingRuleResult *rule_result); + +/** + * Return any matching rule reference to a attribute by name. This is when the matcher should + * be configured to match the type of a structure. I.e., + * + * ```json + * { + * "pact:match": "eachValue(matching($'person'))", + * "person": { + * "name": "Fred", + * "age": 100 + * } + * } + * ``` + * + * Will return a NULL pointer if the matching rule was not a reference. * * # Safety * - * This function is safe. + * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the + * iterator has not been deleted. + */ +const char *pactffi_matching_rule_reference_name(const struct MatchingRuleResult *rule_result); + +/** + * Validates the date/time value against the date/time format string. If the value is valid, + * this function will return a zero status code (EXIT_SUCCESS). + * If the value is not valid, will return a value of 1 (EXIT_FAILURE) and set the + * error message which can be retrieved with `pactffi_get_error_message`. * - * Deleting a message returned by the iterator can lead to undefined behaviour. + * # Errors + * If the function receives a panic, it will return 2 and the message associated with the + * panic can be retrieved with `pactffi_get_error_message`. * - * # Error Handling + * # Safety * - * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + * This function is safe as long as the value and format parameters point to valid + * NULL-terminated strings. */ -struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); +int pactffi_validate_datetime(const char *value, const char *format); + +/** + * Get the JSON form of the generator. + * + * The returned string must be deleted with `pactffi_string_delete`. + * + * # Safety + * + * This function will fail if it is passed a NULL pointer, or the owner of the generator has + * been deleted. + */ +const char *pactffi_generator_to_json(const struct Generator *generator); + +/** + * Generate a string value using the provided generator and an optional JSON payload containing + * any generator context. The context value is used for generators like `MockServerURL` (which + * should contain details about the running mock server) and `ProviderStateGenerator` (which + * should be the values returned from the Provider State callback function). + * + * If anything goes wrong, it will return a NULL pointer. + */ +const char *pactffi_generator_generate_string(const struct Generator *generator, + const char *context_json); + +/** + * Generate an integer value using the provided generator and an optional JSON payload containing + * any generator context. The context value is used for generators like `ProviderStateGenerator` + * (which should be the values returned from the Provider State callback function). + * + * If anything goes wrong or the generator is not a type that can generate an integer value, it + * will return a zero value. + */ +unsigned short pactffi_generator_generate_integer(const struct Generator *generator, + const char *context_json); /** * Free the iterator when you're done using it. */ -void pactffi_pact_sync_message_iter_delete(struct PactSyncMessageIterator *iter); +void pactffi_generators_iter_delete(struct GeneratorCategoryIterator *iter); /** - * Get the next synchronous HTTP request/response interaction from the pact. As the - * interactions returned are owned by the iterator, they do not need to be deleted but - * will be cleaned up when the iterator is deleted. + * Get the next path and generator out of the iterator, if possible. * - * Will return a NULL pointer when the iterator has advanced past the end of the list. + * The returned pointer must be deleted with `pactffi_generator_iter_pair_delete`. * * # Safety * - * This function is safe. - * - * Deleting an interaction returned by the iterator can lead to undefined behaviour. + * The underlying data is owned by the `GeneratorKeyValuePair`, so is always safe to use. * * # Error Handling * - * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + * If no further data is present, returns NULL. */ -struct SynchronousHttp *pactffi_pact_sync_http_iter_next(struct PactSyncHttpIterator *iter); +const struct GeneratorKeyValuePair *pactffi_generators_iter_next(struct GeneratorCategoryIterator *iter); /** - * Free the iterator when you're done using it. + * Free a pair of key and value returned from `pactffi_generators_iter_next`. */ -void pactffi_pact_sync_http_iter_delete(struct PactSyncHttpIterator *iter); +void pactffi_generators_iter_pair_delete(const struct GeneratorKeyValuePair *pair); /** - * Get a mutable pointer to a newly-created default message on the heap. + * Get a mutable pointer to a newly-created default interaction on the heap. * * # Safety * @@ -1207,54 +1616,68 @@ void pactffi_pact_sync_http_iter_delete(struct PactSyncHttpIterator *iter); * * Returns NULL on error. */ -struct SynchronousMessage *pactffi_sync_message_new(void); +struct SynchronousHttp *pactffi_sync_http_new(void); /** - * Destroy the `Message` being pointed to. + * Destroy the `SynchronousHttp` interaction being pointed to. */ -void pactffi_sync_message_delete(struct SynchronousMessage *message); +void pactffi_sync_http_delete(const struct SynchronousHttp *interaction); /** - * Get the request contents of a `SynchronousMessage` in string form. + * Get the request of a `SynchronousHttp` interaction. + * + * # Safety + * + * The data pointed to by the pointer this function returns will be deleted when the interaction + * is deleted. Trying to use if after the interaction is deleted will result in undefined behaviour. + * + * # Error Handling + * + * If the interaction is NULL, returns NULL. + */ +const struct HttpRequest *pactffi_sync_http_get_request(const struct SynchronousHttp *interaction); + +/** + * Get the request contents of a `SynchronousHttp` interaction in string form. * * # Safety * * The returned string must be deleted with `pactffi_string_delete`. * - * The returned string can outlive the message. + * The returned string can outlive the interaction. * * # Error Handling * - * If the message is NULL, returns NULL. If the body of the request message + * If the interaction is NULL, returns NULL. If the body of the request * is missing, then this function also returns NULL. This means there's * no mechanism to differentiate with this function call alone between - * a NULL message and a missing message body. + * a NULL body and a missing body. */ -const char *pactffi_sync_message_get_request_contents(const struct SynchronousMessage *message); +const char *pactffi_sync_http_get_request_contents(const struct SynchronousHttp *interaction); /** - * Sets the request contents of the message. + * Sets the request contents of the interaction. * - * * `message` - the message to set the request contents for + * * `interaction` - the interaction to set the request contents for * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * The message contents and content type must either be NULL pointers, or point to valid + * The request contents and content type must either be NULL pointers, or point to valid * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. * * # Error Handling * - * If the contents is a NULL pointer, it will set the message contents as null. If the content + * If the contents is a NULL pointer, it will set the request contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_message_set_request_contents(struct SynchronousMessage *message, - const char *contents, - const char *content_type); +void pactffi_sync_http_set_request_contents(struct SynchronousHttp *interaction, + const char *contents, + const char *content_type); /** - * Get the length of the request contents of a `SynchronousMessage`. + * Get the length of the request contents of a `SynchronousHttp` interaction. * * # Safety * @@ -1262,31 +1685,31 @@ void pactffi_sync_message_set_request_contents(struct SynchronousMessage *messag * * # Error Handling * - * If the message is NULL, returns 0. If the body of the request + * If the interaction is NULL, returns 0. If the body of the request * is missing, then this function also returns 0. */ -size_t pactffi_sync_message_get_request_contents_length(const struct SynchronousMessage *message); +size_t pactffi_sync_http_get_request_contents_length(const struct SynchronousHttp *interaction); /** - * Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes. + * Get the request contents of a `SynchronousHttp` interaction as a pointer to an array of bytes. * * # Safety * - * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`. - * It is safe to use the pointer while the message is not deleted or changed. Using the pointer - * after the message is mutated or deleted may lead to undefined behaviour. + * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_request_contents_length`. + * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer + * after the interaction is mutated or deleted may lead to undefined behaviour. * * # Error Handling * - * If the message is NULL, returns NULL. If the body of the message + * If the interaction is NULL, returns NULL. If the body of the request * is missing, then this function also returns NULL. */ -const unsigned char *pactffi_sync_message_get_request_contents_bin(const struct SynchronousMessage *message); +const unsigned char *pactffi_sync_http_get_request_contents_bin(const struct SynchronousHttp *interaction); /** - * Sets the request contents of the message as an array of bytes. + * Sets the request contents of the interaction as an array of bytes. * - * * `message` - the message to set the request contents for + * * `interaction` - the interaction to set the request contents for * * `contents` - pointer to contents to copy from * * `len` - number of bytes to copy from the contents pointer * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. @@ -1298,59 +1721,57 @@ const unsigned char *pactffi_sync_message_get_request_contents_bin(const struct * * # Error Handling * - * If the contents is a NULL pointer, it will set the message contents as null. If the content + * If the contents is a NULL pointer, it will set the request contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_message_set_request_contents_bin(struct SynchronousMessage *message, - const unsigned char *contents, - size_t len, - const char *content_type); +void pactffi_sync_http_set_request_contents_bin(struct SynchronousHttp *interaction, + const unsigned char *contents, + size_t len, + const char *content_type); /** - * Get the number of response messages in the `SynchronousMessage`. + * Get the response of a `SynchronousHttp` interaction. * * # Safety * - * The message pointer must point to a valid SynchronousMessage. + * The data pointed to by the pointer this function returns will be deleted when the interaction + * is deleted. Trying to use if after the interaction is deleted will result in undefined behaviour. * * # Error Handling * - * If the message is NULL, returns 0. + * If the interaction is NULL, returns NULL. */ -size_t pactffi_sync_message_get_number_responses(const struct SynchronousMessage *message); +const struct HttpResponse *pactffi_sync_http_get_response(const struct SynchronousHttp *interaction); /** - * Get the response contents of a `SynchronousMessage` in string form. + * Get the response contents of a `SynchronousHttp` interaction in string form. * * # Safety * * The returned string must be deleted with `pactffi_string_delete`. * - * The returned string can outlive the message. + * The returned string can outlive the interaction. * * # Error Handling * - * If the message is NULL or the index is not valid, returns NULL. + * If the interaction is NULL, returns NULL. * - * If the body of the response message is missing, then this function also returns NULL. + * If the body of the response is missing, then this function also returns NULL. * This means there's no mechanism to differentiate with this function call alone between - * a NULL message and a missing message body. + * a NULL body and a missing body. */ -const char *pactffi_sync_message_get_response_contents(const struct SynchronousMessage *message, - size_t index); +const char *pactffi_sync_http_get_response_contents(const struct SynchronousHttp *interaction); /** - * Sets the response contents of the message. If index is greater than the number of responses - * in the message, the responses will be padded with default values. + * Sets the response contents of the interaction. * - * * `message` - the message to set the response contents for - * * `index` - index of the response to set. 0 is the first response. + * * `interaction` - the interaction to set the response contents for * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * The message contents and content type must either be NULL pointers, or point to valid + * The response contents and content type must either be NULL pointers, or point to valid * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. * * # Error Handling @@ -1358,13 +1779,12 @@ const char *pactffi_sync_message_get_response_contents(const struct SynchronousM * If the contents is a NULL pointer, it will set the response contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_message_set_response_contents(struct SynchronousMessage *message, - size_t index, - const char *contents, - const char *content_type); +void pactffi_sync_http_set_response_contents(struct SynchronousHttp *interaction, + const char *contents, + const char *content_type); /** - * Get the length of the response contents of a `SynchronousMessage`. + * Get the length of the response contents of a `SynchronousHttp` interaction. * * # Safety * @@ -1372,36 +1792,31 @@ void pactffi_sync_message_set_response_contents(struct SynchronousMessage *messa * * # Error Handling * - * If the message is NULL or the index is not valid, returns 0. If the body of the request + * If the interaction is NULL or the index is not valid, returns 0. If the body of the response * is missing, then this function also returns 0. */ -size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, - size_t index); +size_t pactffi_sync_http_get_response_contents_length(const struct SynchronousHttp *interaction); /** - * Get the response contents of a `SynchronousMessage` as a pointer to an array of bytes. + * Get the response contents of a `SynchronousHttp` interaction as a pointer to an array of bytes. * * # Safety * - * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_response_contents_length`. - * It is safe to use the pointer while the message is not deleted or changed. Using the pointer - * after the message is mutated or deleted may lead to undefined behaviour. + * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_response_contents_length`. + * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer + * after the interaction is mutated or deleted may lead to undefined behaviour. * * # Error Handling * - * If the message is NULL or the index is not valid, returns NULL. If the body of the message + * If the interaction is NULL, returns NULL. If the body of the response * is missing, then this function also returns NULL. */ -const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, - size_t index); +const unsigned char *pactffi_sync_http_get_response_contents_bin(const struct SynchronousHttp *interaction); /** - * Sets the response contents of the message at the given index as an array of bytes. If index - * is greater than the number of responses in the message, the responses will be padded with - * default values. + * Sets the response contents of the `SynchronousHttp` interaction as an array of bytes. * - * * `message` - the message to set the response contents for - * * `index` - index of the response to set. 0 is the first response + * * `interaction` - the interaction to set the response contents for * * `contents` - pointer to contents to copy from * * `len` - number of bytes to copy * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. @@ -1413,14 +1828,13 @@ const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct * * # Error Handling * - * If the contents is a NULL pointer, it will set the message contents as null. If the content + * If the contents is a NULL pointer, it will set the response contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_message_set_response_contents_bin(struct SynchronousMessage *message, - size_t index, - const unsigned char *contents, - size_t len, - const char *content_type); +void pactffi_sync_http_set_response_contents_bin(struct SynchronousHttp *interaction, + const unsigned char *contents, + size_t len, + const char *content_type); /** * Get a copy of the description. @@ -1430,7 +1844,7 @@ void pactffi_sync_message_set_response_contents_bin(struct SynchronousMessage *m * The returned string must be deleted with `pactffi_string_delete`. * * Since it is a copy, the returned string may safely outlive - * the `SynchronousMessage`. + * the `SynchronousHttp` interaction. * * # Errors * @@ -1439,10 +1853,10 @@ void pactffi_sync_message_set_response_contents_bin(struct SynchronousMessage *m * This function may fail if the Rust string contains embedded * null ('\0') bytes. */ -const char *pactffi_sync_message_get_description(const struct SynchronousMessage *message); +const char *pactffi_sync_http_get_description(const struct SynchronousHttp *interaction); /** - * Write the `description` field on the `SynchronousMessage`. + * Write the `description` field on the `SynchronousHttp`. * * # Safety * @@ -1454,46 +1868,850 @@ const char *pactffi_sync_message_get_description(const struct SynchronousMessage * * # Error Handling * - * Errors will be reported with a non-zero return value. + * Errors will be reported with a non-zero return value. + */ +int pactffi_sync_http_set_description(struct SynchronousHttp *interaction, const char *description); + +/** + * Get a copy of the provider state at the given index from this interaction. + * + * # Safety + * + * The returned structure must be deleted with `provider_state_delete`. + * + * Since it is a copy, the returned structure may safely outlive + * the `SynchronousHttp`. + * + * # Error Handling + * + * On failure, this function will return a variant other than Success. + * + * This function may fail if the index requested is out of bounds, + * or if any of the Rust strings contain embedded null ('\0') bytes. + */ +const struct ProviderState *pactffi_sync_http_get_provider_state(const struct SynchronousHttp *interaction, + unsigned int index); + +/** + * Get an iterator over provider states. + * + * # Safety + * + * The underlying data must not change during iteration. + * + * # Error Handling + * + * Returns NULL if an error occurs. + */ +struct ProviderStateIterator *pactffi_sync_http_get_provider_state_iter(struct SynchronousHttp *interaction); + +/** + * Casts this interaction to a `SynchronousHttp` interaction. Returns a NULL pointer if the + * interaction can not be casted to a `SynchronousHttp` interaction (for instance, it is a + * message interaction). The returned pointer must be freed with `pactffi_sync_http_delete` + * when no longer required. + * + * # Safety + * This function is safe as long as the interaction pointer is a valid pointer. + * + * # Errors + * On any error, this function will return a NULL pointer. + */ +const struct SynchronousHttp *pactffi_pact_interaction_as_synchronous_http(const struct PactInteraction *interaction); + +/** + * Casts this interaction to a `Message` interaction. Returns a NULL pointer if the + * interaction can not be casted to a `Message` interaction (for instance, it is a + * http interaction). The returned pointer must be freed with `pactffi_message_delete` + * when no longer required. + * + * Note that if the interaction is a V4 `AsynchronousMessage`, it will be converted to a V3 + * `Message` before being returned. + * + * # Safety + * This function is safe as long as the interaction pointer is a valid pointer. + * + * # Errors + * On any error, this function will return a NULL pointer. + */ +const struct Message *pactffi_pact_interaction_as_message(const struct PactInteraction *interaction); + +/** + * Casts this interaction to a `AsynchronousMessage` interaction. Returns a NULL pointer if the + * interaction can not be casted to a `AsynchronousMessage` interaction (for instance, it is a + * http interaction). The returned pointer must be freed with `pactffi_async_message_delete` + * when no longer required. + * + * Note that if the interaction is a V3 `Message`, it will be converted to a V4 + * `AsynchronousMessage` before being returned. + * + * # Safety + * This function is safe as long as the interaction pointer is a valid pointer. + * + * # Errors + * On any error, this function will return a NULL pointer. + */ +const struct AsynchronousMessage *pactffi_pact_interaction_as_asynchronous_message(const struct PactInteraction *interaction); + +/** + * Casts this interaction to a `SynchronousMessage` interaction. Returns a NULL pointer if the + * interaction can not be casted to a `SynchronousMessage` interaction (for instance, it is a + * http interaction). The returned pointer must be freed with `pactffi_sync_message_delete` + * when no longer required. + * + * # Safety + * This function is safe as long as the interaction pointer is a valid pointer. + * + * # Errors + * On any error, this function will return a NULL pointer. + */ +const struct SynchronousMessage *pactffi_pact_interaction_as_synchronous_message(const struct PactInteraction *interaction); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_pact_message_iter_delete(struct PactMessageIterator *iter); + +/** + * Get the next message from the message pact. As the messages returned are owned by the + * iterator, they do not need to be deleted but will be cleaned up when the iterator is + * deleted. + * + * Will return a NULL pointer when the iterator has advanced past the end of the list. + * + * # Safety + * + * This function is safe. + * + * Deleting a message returned by the iterator can lead to undefined behaviour. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); + +/** + * Get the next asynchronous from the V4 pact. As the messages returned are + * owned by the iterator, they do not need to be deleted but will be + * cleaned up when the iterator is deleted. + * + * Will return a NULL pointer when the iterator has advanced past the end + * of the list. + * + * # Safety + * + * This function is safe. + * + * Deleting a message returned by the iterator can lead to undefined + * behaviour. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if + * an error occurs. + */ +struct AsynchronousMessage *pactffi_pact_async_message_iter_next(struct PactAsyncMessageIterator *iter); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_pact_async_message_iter_delete(struct PactAsyncMessageIterator *iter); + +/** + * Get the next synchronous request/response message from the V4 pact. As the messages returned are owned by the + * iterator, they do not need to be deleted but will be cleaned up when the iterator is + * deleted. + * + * Will return a NULL pointer when the iterator has advanced past the end of the list. + * + * # Safety + * + * This function is safe. + * + * Deleting a message returned by the iterator can lead to undefined behaviour. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_pact_sync_message_iter_delete(struct PactSyncMessageIterator *iter); + +/** + * Get the next synchronous HTTP request/response interaction from the V4 pact. As the + * interactions returned are owned by the iterator, they do not need to be deleted but + * will be cleaned up when the iterator is deleted. + * + * Will return a NULL pointer when the iterator has advanced past the end of the list. + * + * # Safety + * + * This function is safe. + * + * Deleting an interaction returned by the iterator can lead to undefined behaviour. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +struct SynchronousHttp *pactffi_pact_sync_http_iter_next(struct PactSyncHttpIterator *iter); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_pact_sync_http_iter_delete(struct PactSyncHttpIterator *iter); + +/** + * Get the next interaction from the pact. As the interactions returned are owned by the + * iterator, they do not need to be deleted but will be cleaned up when the iterator is + * deleted. + * + * Will return a NULL pointer when the iterator has advanced past the end of the list. + * + * # Safety + * + * This function is safe. + * + * Deleting an interaction returned by the iterator can lead to undefined behaviour. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +const struct PactInteraction *pactffi_pact_interaction_iter_next(struct PactInteractionIterator *iter); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_pact_interaction_iter_delete(struct PactInteractionIterator *iter); + +/** + * Get the JSON form of the matching rule. + * + * The returned string must be deleted with `pactffi_string_delete`. + * + * # Safety + * + * This function will fail if it is passed a NULL pointer, or the iterator that owns the + * value of the matching rule has been deleted. + */ +const char *pactffi_matching_rule_to_json(const struct MatchingRule *rule); + +/** + * Free the iterator when you're done using it. + */ +void pactffi_matching_rules_iter_delete(struct MatchingRuleCategoryIterator *iter); + +/** + * Get the next path and matching rule out of the iterator, if possible. + * + * The returned pointer must be deleted with `pactffi_matching_rules_iter_pair_delete`. + * + * # Safety + * + * The underlying data is owned by the `MatchingRuleKeyValuePair`, so is always safe to use. + * + * # Error Handling + * + * If no further data is present, returns NULL. + */ +const struct MatchingRuleKeyValuePair *pactffi_matching_rules_iter_next(struct MatchingRuleCategoryIterator *iter); + +/** + * Free a pair of key and value returned from `message_metadata_iter_next`. + */ +void pactffi_matching_rules_iter_pair_delete(const struct MatchingRuleKeyValuePair *pair); + +/** + * Get a mutable pointer to a newly-created default message on the heap. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * Returns NULL on error. + */ +struct Message *pactffi_message_new(void); + +/** + * Constructs a `Message` from the JSON string + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * If the JSON string is invalid or not UTF-8 encoded, returns a NULL. + */ +struct Message *pactffi_message_new_from_json(unsigned int index, + const char *json_str, + int spec_version); + +/** + * Constructs a `Message` from a body with a given content-type. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * If the body or content type are invalid or not UTF-8 encoded, returns NULL. + */ +struct Message *pactffi_message_new_from_body(const char *body, const char *content_type); + +/** + * Destroy the `Message` being pointed to. + */ +void pactffi_message_delete(struct Message *message); + +/** + * Get the contents of a `Message` in string form. + * + * # Safety + * + * The returned string must be deleted with `pactffi_string_delete` and can outlive the message. + * This function must only ever be called from a foreign language. Calling it from a Rust function + * that has a Tokio runtime in its call stack can result in a deadlock. + * + * # Error Handling + * + * If the message is NULL, returns NULL. If the body of the message + * is missing, then this function also returns NULL. This means there's + * no mechanism to differentiate with this function call alone between + * a NULL message and a missing message body. + */ +const char *pactffi_message_get_contents(const struct Message *message); + +/** + * Sets the contents of the message. + * + * # Safety + * + * The message contents and content type must either be NULL pointers, or point to valid + * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. + * + * # Error Handling + * + * If the contents is a NULL pointer, it will set the message contents as null. If the content + * type is a null pointer, or can't be parsed, it will set the content type as unknown. + */ +void pactffi_message_set_contents(struct Message *message, + const char *contents, + const char *content_type); + +/** + * Get the length of the contents of a `Message`. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * If the message is NULL, returns 0. If the body of the message + * is missing, then this function also returns 0. + */ +size_t pactffi_message_get_contents_length(const struct Message *message); + +/** + * Get the contents of a `Message` as a pointer to an array of bytes. + * + * # Safety + * + * The number of bytes in the buffer will be returned by `pactffi_message_get_contents_length`. + * It is safe to use the pointer while the message is not deleted or changed. Using the pointer + * after the message is mutated or deleted may lead to undefined behaviour. + * + * # Error Handling + * + * If the message is NULL, returns NULL. If the body of the message + * is missing, then this function also returns NULL. + */ +const unsigned char *pactffi_message_get_contents_bin(const struct Message *message); + +/** + * Sets the contents of the message as an array of bytes. + * + * # Safety + * + * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned + * and consecutive. Otherwise behaviour is undefined. + * + * # Error Handling + * + * If the contents is a NULL pointer, it will set the message contents as null. If the content + * type is a null pointer, or can't be parsed, it will set the content type as unknown. + */ +void pactffi_message_set_contents_bin(struct Message *message, + const unsigned char *contents, + size_t len, + const char *content_type); + +/** + * Get a copy of the description. + * + * # Safety + * + * The returned string must be deleted with `pactffi_string_delete`. + * + * Since it is a copy, the returned string may safely outlive + * the `Message`. + * + * # Errors + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if the Rust string contains embedded + * null ('\0') bytes. + */ +const char *pactffi_message_get_description(const struct Message *message); + +/** + * Write the `description` field on the `Message`. + * + * # Safety + * + * `description` must contain valid UTF-8. Invalid UTF-8 + * will be replaced with U+FFFD REPLACEMENT CHARACTER. + * + * This function will only reallocate if the new string + * does not fit in the existing buffer. + * + * # Error Handling + * + * Errors will be reported with a non-zero return value. + */ +int pactffi_message_set_description(struct Message *message, const char *description); + +/** + * Get a copy of the provider state at the given index from this message. + * + * # Safety + * + * The returned structure must be deleted with `provider_state_delete`. + * + * Since it is a copy, the returned structure may safely outlive + * the `Message`. + * + * # Error Handling + * + * On failure, this function will return a variant other than Success. + * + * This function may fail if the index requested is out of bounds, + * or if any of the Rust strings contain embedded null ('\0') bytes. + */ +const struct ProviderState *pactffi_message_get_provider_state(const struct Message *message, + unsigned int index); + +/** + * Get an iterator over provider states. + * + * # Safety + * + * The underlying data must not change during iteration. + * + * # Error Handling + * + * Returns NULL if an error occurs. + */ +struct ProviderStateIterator *pactffi_message_get_provider_state_iter(struct Message *message); + +/** + * Get the next value from the iterator. + * + * # Safety + * + * The underlying data must not change during iteration. + * + * If a previous call panicked, then the internal mutex will have been poisoned and this + * function will return NULL. + * + * # Error Handling + * + * Returns NULL if an error occurs. + */ +struct ProviderState *pactffi_provider_state_iter_next(struct ProviderStateIterator *iter); + +/** + * Delete the iterator. + */ +void pactffi_provider_state_iter_delete(struct ProviderStateIterator *iter); + +/** + * Get a copy of the metadata value indexed by `key`. + * + * # Safety + * + * The returned string must be deleted with `pactffi_string_delete`. + * + * Since it is a copy, the returned string may safely outlive + * the `Message`. + * + * The returned pointer will be NULL if the metadata does not contain + * the given key, or if an error occurred. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if the provided `key` string contains + * invalid UTF-8, or if the Rust string contains embedded null ('\0') + * bytes. + */ +const char *pactffi_message_find_metadata(const struct Message *message, const char *key); + +/** + * Insert the (`key`, `value`) pair into this Message's + * `metadata` HashMap. + * + * # Safety + * + * This function returns an enum indicating the result; + * see the comments on HashMapInsertStatus for details. + * + * # Error Handling + * + * This function may fail if the provided `key` or `value` strings + * contain invalid UTF-8. + */ +int pactffi_message_insert_metadata(struct Message *message, const char *key, const char *value); + +/** + * Get the next key and value out of the iterator, if possible. + * + * The returned pointer must be deleted with `pactffi_message_metadata_pair_delete`. + * + * # Safety + * + * The underlying data must not change during iteration. + * This function must only ever be called from a foreign language. Calling it from a Rust function + * that has a Tokio runtime in its call stack can result in a deadlock. + * + * # Error Handling + * + * If no further data is present, returns NULL. + */ +struct MessageMetadataPair *pactffi_message_metadata_iter_next(struct MessageMetadataIterator *iter); + +/** + * Get an iterator over the metadata of a message. + * + * # Safety + * + * This iterator carries a pointer to the message, and must + * not outlive the message. + * + * The message metadata also must not be modified during iteration. If it is, + * the old iterator must be deleted and a new iterator created. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if any of the Rust strings contain + * embedded null ('\0') bytes. + */ +struct MessageMetadataIterator *pactffi_message_get_metadata_iter(struct Message *message); + +/** + * Free the metadata iterator when you're done using it. + */ +void pactffi_message_metadata_iter_delete(struct MessageMetadataIterator *iter); + +/** + * Free a pair of key and value returned from `message_metadata_iter_next`. + */ +void pactffi_message_metadata_pair_delete(struct MessageMetadataPair *pair); + +/** + * Construct a new `MessagePact` from the JSON string. + * The provided file name is used when generating error messages. + * + * # Safety + * + * The `file_name` and `json_str` parameters must both be valid UTF-8 + * encoded strings. + * + * # Error Handling + * + * On error, this function will return a null pointer. + */ +struct MessagePact *pactffi_message_pact_new_from_json(const char *file_name, const char *json_str); + +/** + * Delete the `MessagePact` being pointed to. + */ +void pactffi_message_pact_delete(struct MessagePact *message_pact); + +/** + * Get a pointer to the Consumer struct inside the MessagePact. + * This is a mutable borrow: The caller may mutate the Consumer + * through this pointer. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * This function will only fail if it is passed a NULL pointer. + * In the case of error, a NULL pointer will be returned. + */ +struct Consumer *pactffi_message_pact_get_consumer(struct MessagePact *message_pact); + +/** + * Get a pointer to the Provider struct inside the MessagePact. + * This is a mutable borrow: The caller may mutate the Provider + * through this pointer. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * This function will only fail if it is passed a NULL pointer. + * In the case of error, a NULL pointer will be returned. + */ +struct Provider *pactffi_message_pact_get_provider(struct MessagePact *message_pact); + +/** + * Get an iterator over the messages of a message pact. + * + * # Safety + * + * This iterator carries a pointer to the message pact, and must + * not outlive the message pact. + * + * The message pact messages also must not be modified during iteration. + * If they are, the old iterator must be deleted and a new iterator created. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if any of the Rust strings contain embedded + * null ('\0') bytes. + */ +struct MessagePactMessageIterator *pactffi_message_pact_get_message_iter(struct MessagePact *message_pact); + +/** + * Get the next message from the message pact. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * This function will return a NULL pointer if passed a NULL pointer or if an error occurs. + */ +struct Message *pactffi_message_pact_message_iter_next(struct MessagePactMessageIterator *iter); + +/** + * Delete the iterator. + */ +void pactffi_message_pact_message_iter_delete(struct MessagePactMessageIterator *iter); + +/** + * Get a copy of the metadata value indexed by `key1` and `key2`. + * + * # Safety + * + * Since it is a copy, the returned string may safely outlive + * the `Message`. + * + * The returned string must be deleted with `pactffi_string_delete`. + * + * The returned pointer will be NULL if the metadata does not contain + * the given key, or if an error occurred. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if the provided `key1` or `key2` strings contains + * invalid UTF-8, or if the Rust string contains embedded null ('\0') + * bytes. + */ +const char *pactffi_message_pact_find_metadata(const struct MessagePact *message_pact, + const char *key1, + const char *key2); + +/** + * Get an iterator over the metadata of a message pact. + * + * # Safety + * + * This iterator carries a pointer to the message pact, and must + * not outlive the message pact. + * + * The message pact metadata also must not be modified during iteration. If it is, + * the old iterator must be deleted and a new iterator created. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if any of the Rust strings contain + * embedded null ('\0') bytes. + */ +struct MessagePactMetadataIterator *pactffi_message_pact_get_metadata_iter(struct MessagePact *message_pact); + +/** + * Get the next triple out of the iterator, if possible + * + * # Safety + * + * This operation is invalid if the underlying data has been changed during iteration. + * + * # Error Handling + * + * Returns null if no next element is present. + */ +struct MessagePactMetadataTriple *pactffi_message_pact_metadata_iter_next(struct MessagePactMetadataIterator *iter); + +/** + * Free the metadata iterator when you're done using it. + */ +void pactffi_message_pact_metadata_iter_delete(struct MessagePactMetadataIterator *iter); + +/** + * Free a triple returned from `pactffi_message_pact_metadata_iter_next`. + */ +void pactffi_message_pact_metadata_triple_delete(struct MessagePactMetadataTriple *triple); + +/** + * Get a copy of this provider's name. + * + * The copy must be deleted with `pactffi_string_delete`. + * + * # Usage + * + * ```c + * // Assuming `file_name` and `json_str` are already defined. + * + * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str); + * if (message_pact == NULLPTR) { + * // handle error. + * } + * + * Provider *provider = pactffi_message_pact_get_provider(message_pact); + * if (provider == NULLPTR) { + * // handle error. + * } + * + * char *name = pactffi_provider_get_name(provider); + * if (name == NULL) { + * // handle error. + * } + * + * printf("%s\n", name); + * + * pactffi_string_delete(name); + * ``` + * + * # Errors + * + * This function will fail if it is passed a NULL pointer, + * or the Rust string contains an embedded NULL byte. + * In the case of error, a NULL pointer will be returned. + */ +const char *pactffi_provider_get_name(const struct Provider *provider); + +/** + * Get the provider from a Pact. This returns a copy of the provider model, and needs to + * be cleaned up with `pactffi_pact_provider_delete` when no longer required. + * + * # Errors + * + * This function will fail if it is passed a NULL pointer. + * In the case of error, a NULL pointer will be returned. + */ +const struct Provider *pactffi_pact_get_provider(const struct Pact *pact); + +/** + * Frees the memory used by the Pact provider + */ +void pactffi_pact_provider_delete(const struct Provider *provider); + +/** + * Get the name of the provider state as a string, which needs to be deleted with `pactffi_string_delete`. + * + * # Safety + * + * This function is safe. + * + * # Error Handling + * + * If the provider_state param is NULL, this returns NULL. */ -int pactffi_sync_message_set_description(struct SynchronousMessage *message, - const char *description); +const char *pactffi_provider_state_get_name(const struct ProviderState *provider_state); /** - * Get a copy of the provider state at the given index from this message. + * Get an iterator over the params of a provider state. * * # Safety * - * The returned structure must be deleted with `provider_state_delete`. + * This iterator carries a pointer to the provider state, and must + * not outlive the provider state. * - * Since it is a copy, the returned structure may safely outlive - * the `SynchronousMessage`. + * The provider state params also must not be modified during iteration. If it is, + * the old iterator must be deleted and a new iterator created. * - * # Error Handling + * # Errors * - * On failure, this function will return a variant other than Success. + * On failure, this function will return a NULL pointer. * - * This function may fail if the index requested is out of bounds, - * or if any of the Rust strings contain embedded null ('\0') bytes. + * This function may fail if any of the Rust strings contain + * embedded null ('\0') bytes. */ -const struct ProviderState *pactffi_sync_message_get_provider_state(const struct SynchronousMessage *message, - unsigned int index); +struct ProviderStateParamIterator *pactffi_provider_state_get_param_iter(struct ProviderState *provider_state); /** - * Get an iterator over provider states. + * Get the next key and value out of the iterator, if possible + * + * Returns a pointer to a heap allocated array of 2 elements, the pointer to the + * key string on the heap, and the pointer to the value string on the heap. * * # Safety * - * The underlying data must not change during iteration. + * The underlying data must not be modified during iteration. + * + * The user needs to free both the contained strings and the array. * * # Error Handling * - * Returns NULL if an error occurs. + * Returns NULL if there's no further elements or the iterator is NULL. */ -struct ProviderStateIterator *pactffi_sync_message_get_provider_state_iter(struct SynchronousMessage *message); +struct ProviderStateParamPair *pactffi_provider_state_param_iter_next(struct ProviderStateParamIterator *iter); /** - * Get a mutable pointer to a newly-created default interaction on the heap. + * Free the provider state when you're done using it. + */ +void pactffi_provider_state_delete(struct ProviderState *provider_state); + +/** + * Free the provider state param iterator when you're done using it. + */ +void pactffi_provider_state_param_iter_delete(struct ProviderStateParamIterator *iter); + +/** + * Free a pair of key and value returned from `pactffi_provider_state_param_iter_next`. + */ +void pactffi_provider_state_param_pair_delete(struct ProviderStateParamPair *pair); + +/** + * Get a mutable pointer to a newly-created default message on the heap. * * # Safety * @@ -1503,54 +2721,54 @@ struct ProviderStateIterator *pactffi_sync_message_get_provider_state_iter(struc * * Returns NULL on error. */ -struct SynchronousHttp *pactffi_sync_http_new(void); +struct SynchronousMessage *pactffi_sync_message_new(void); /** - * Destroy the `SynchronousHttp` interaction being pointed to. + * Destroy the `Message` being pointed to. */ -void pactffi_sync_http_delete(struct SynchronousHttp *interaction); +void pactffi_sync_message_delete(struct SynchronousMessage *message); /** - * Get the request contents of a `SynchronousHttp` interaction in string form. + * Get the request contents of a `SynchronousMessage` in string form. * * # Safety * * The returned string must be deleted with `pactffi_string_delete`. * - * The returned string can outlive the interaction. + * The returned string can outlive the message. * * # Error Handling * - * If the interaction is NULL, returns NULL. If the body of the request + * If the message is NULL, returns NULL. If the body of the request message * is missing, then this function also returns NULL. This means there's * no mechanism to differentiate with this function call alone between - * a NULL body and a missing body. + * a NULL message and a missing message body. */ -const char *pactffi_sync_http_get_request_contents(const struct SynchronousHttp *interaction); +const char *pactffi_sync_message_get_request_contents_str(const struct SynchronousMessage *message); /** - * Sets the request contents of the interaction. + * Sets the request contents of the message. * - * * `interaction` - the interaction to set the request contents for + * * `message` - the message to set the request contents for * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * The request contents and content type must either be NULL pointers, or point to valid + * The message contents and content type must either be NULL pointers, or point to valid * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. * * # Error Handling * - * If the contents is a NULL pointer, it will set the request contents as null. If the content + * If the contents is a NULL pointer, it will set the message contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_http_set_request_contents(struct SynchronousHttp *interaction, - const char *contents, - const char *content_type); +void pactffi_sync_message_set_request_contents_str(struct SynchronousMessage *message, + const char *contents, + const char *content_type); /** - * Get the length of the request contents of a `SynchronousHttp` interaction. + * Get the length of the request contents of a `SynchronousMessage`. * * # Safety * @@ -1558,31 +2776,31 @@ void pactffi_sync_http_set_request_contents(struct SynchronousHttp *interaction, * * # Error Handling * - * If the interaction is NULL, returns 0. If the body of the request + * If the message is NULL, returns 0. If the body of the request * is missing, then this function also returns 0. */ -size_t pactffi_sync_http_get_request_contents_length(const struct SynchronousHttp *interaction); +size_t pactffi_sync_message_get_request_contents_length(const struct SynchronousMessage *message); /** - * Get the request contents of a `SynchronousHttp` interaction as a pointer to an array of bytes. + * Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes. * * # Safety * - * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_request_contents_length`. - * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer - * after the interaction is mutated or deleted may lead to undefined behaviour. + * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`. + * It is safe to use the pointer while the message is not deleted or changed. Using the pointer + * after the message is mutated or deleted may lead to undefined behaviour. * * # Error Handling * - * If the interaction is NULL, returns NULL. If the body of the request + * If the message is NULL, returns NULL. If the body of the message * is missing, then this function also returns NULL. */ -const unsigned char *pactffi_sync_http_get_request_contents_bin(const struct SynchronousHttp *interaction); +const unsigned char *pactffi_sync_message_get_request_contents_bin(const struct SynchronousMessage *message); /** - * Sets the request contents of the interaction as an array of bytes. + * Sets the request contents of the message as an array of bytes. * - * * `interaction` - the interaction to set the request contents for + * * `message` - the message to set the request contents for * * `contents` - pointer to contents to copy from * * `len` - number of bytes to copy from the contents pointer * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. @@ -1594,43 +2812,93 @@ const unsigned char *pactffi_sync_http_get_request_contents_bin(const struct Syn * * # Error Handling * - * If the contents is a NULL pointer, it will set the request contents as null. If the content + * If the contents is a NULL pointer, it will set the message contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_http_set_request_contents_bin(struct SynchronousHttp *interaction, - const unsigned char *contents, - size_t len, - const char *content_type); +void pactffi_sync_message_set_request_contents_bin(struct SynchronousMessage *message, + const unsigned char *contents, + size_t len, + const char *content_type); /** - * Get the response contents of a `SynchronousHttp` interaction in string form. + * Get the request contents of an `SynchronousMessage` as a `MessageContents` pointer. + * + * # Safety + * + * The data pointed to by the pointer this function returns will be deleted when the message + * is deleted. Trying to use if after the message is deleted will result in undefined behaviour. + * + * # Error Handling + * + * If the message is NULL, returns NULL. + */ +const struct MessageContents *pactffi_sync_message_get_request_contents(const struct SynchronousMessage *message); + +/** + * Generate the request contents of a `SynchronousMessage` as a + * `MessageContents` pointer. + * + * This function differs from [`pactffi_sync_message_get_request_contents`] + * in that it will process the message contents for any generators or + * matchers that are present in the message in order to generate the actual + * message contents as would be received by the consumer. + * + * # Safety + * + * The data pointed to by the pointer must be deleted with + * [`pactffi_message_contents_delete`][crate::models::contents::pactffi_message_contents_delete] + * + * # Error Handling + * + * If the message is NULL, returns NULL. + */ +const struct MessageContents *pactffi_sync_message_generate_request_contents(const struct SynchronousMessage *message); + +/** + * Get the number of response messages in the `SynchronousMessage`. + * + * # Safety + * + * The message pointer must point to a valid SynchronousMessage. + * + * # Error Handling + * + * If the message is NULL, returns 0. + */ +size_t pactffi_sync_message_get_number_responses(const struct SynchronousMessage *message); + +/** + * Get the response contents of a `SynchronousMessage` in string form. * * # Safety * * The returned string must be deleted with `pactffi_string_delete`. * - * The returned string can outlive the interaction. + * The returned string can outlive the message. * * # Error Handling * - * If the interaction is NULL, returns NULL. + * If the message is NULL or the index is not valid, returns NULL. * - * If the body of the response is missing, then this function also returns NULL. + * If the body of the response message is missing, then this function also returns NULL. * This means there's no mechanism to differentiate with this function call alone between - * a NULL body and a missing body. + * a NULL message and a missing message body. */ -const char *pactffi_sync_http_get_response_contents(const struct SynchronousHttp *interaction); +const char *pactffi_sync_message_get_response_contents_str(const struct SynchronousMessage *message, + size_t index); /** - * Sets the response contents of the interaction. + * Sets the response contents of the message as a string. If index is greater than the number of responses + * in the message, the responses will be padded with default values. * - * * `interaction` - the interaction to set the response contents for + * * `message` - the message to set the response contents for + * * `index` - index of the response to set. 0 is the first response. * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer. * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. * * # Safety * - * The response contents and content type must either be NULL pointers, or point to valid + * The message contents and content type must either be NULL pointers, or point to valid * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined. * * # Error Handling @@ -1638,12 +2906,13 @@ const char *pactffi_sync_http_get_response_contents(const struct SynchronousHttp * If the contents is a NULL pointer, it will set the response contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_http_set_response_contents(struct SynchronousHttp *interaction, - const char *contents, - const char *content_type); +void pactffi_sync_message_set_response_contents_str(struct SynchronousMessage *message, + size_t index, + const char *contents, + const char *content_type); /** - * Get the length of the response contents of a `SynchronousHttp` interaction. + * Get the length of the response contents of a `SynchronousMessage`. * * # Safety * @@ -1651,31 +2920,36 @@ void pactffi_sync_http_set_response_contents(struct SynchronousHttp *interaction * * # Error Handling * - * If the interaction is NULL or the index is not valid, returns 0. If the body of the response + * If the message is NULL or the index is not valid, returns 0. If the body of the request * is missing, then this function also returns 0. */ -size_t pactffi_sync_http_get_response_contents_length(const struct SynchronousHttp *interaction); +size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, + size_t index); /** - * Get the response contents of a `SynchronousHttp` interaction as a pointer to an array of bytes. + * Get the response contents of a `SynchronousMessage` as a pointer to an array of bytes. * * # Safety * - * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_response_contents_length`. - * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer - * after the interaction is mutated or deleted may lead to undefined behaviour. + * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_response_contents_length`. + * It is safe to use the pointer while the message is not deleted or changed. Using the pointer + * after the message is mutated or deleted may lead to undefined behaviour. * * # Error Handling * - * If the interaction is NULL, returns NULL. If the body of the response + * If the message is NULL or the index is not valid, returns NULL. If the body of the message * is missing, then this function also returns NULL. */ -const unsigned char *pactffi_sync_http_get_response_contents_bin(const struct SynchronousHttp *interaction); +const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, + size_t index); /** - * Sets the response contents of the `SynchronousHttp` interaction as an array of bytes. + * Sets the response contents of the message at the given index as an array of bytes. If index + * is greater than the number of responses in the message, the responses will be padded with + * default values. * - * * `interaction` - the interaction to set the response contents for + * * `message` - the message to set the response contents for + * * `index` - index of the response to set. 0 is the first response * * `contents` - pointer to contents to copy from * * `len` - number of bytes to copy * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data. @@ -1687,13 +2961,51 @@ const unsigned char *pactffi_sync_http_get_response_contents_bin(const struct Sy * * # Error Handling * - * If the contents is a NULL pointer, it will set the response contents as null. If the content + * If the contents is a NULL pointer, it will set the message contents as null. If the content * type is a null pointer, or can't be parsed, it will set the content type as unknown. */ -void pactffi_sync_http_set_response_contents_bin(struct SynchronousHttp *interaction, - const unsigned char *contents, - size_t len, - const char *content_type); +void pactffi_sync_message_set_response_contents_bin(struct SynchronousMessage *message, + size_t index, + const unsigned char *contents, + size_t len, + const char *content_type); + +/** + * Get the response contents of an `SynchronousMessage` as a `MessageContents` pointer. + * + * # Safety + * + * The data pointed to by the pointer this function returns will be deleted when the message + * is deleted. Trying to use if after the message is deleted will result in undefined behaviour. + * + * # Error Handling + * + * If the message is NULL or the index is not valid, returns NULL. + */ +const struct MessageContents *pactffi_sync_message_get_response_contents(const struct SynchronousMessage *message, + size_t index); + +/** + * Generate the response contents of a `SynchronousMessage` as a + * `MessageContents` pointer. + * + * This function differs from + * [`pactffi_sync_message_get_response_contents`] in that it will process + * the message contents for any generators or matchers that are present in + * the message in order to generate the actual message contents as would be + * received by the consumer. + * + * # Safety + * + * The data pointed to by the pointer must be deleted with + * [`pactffi_message_contents_delete`][crate::models::contents::pactffi_message_contents_delete] + * + * # Error Handling + * + * If the message is NULL, returns NULL. + */ +const struct MessageContents *pactffi_sync_message_generate_response_contents(const struct SynchronousMessage *message, + size_t index); /** * Get a copy of the description. @@ -1703,7 +3015,7 @@ void pactffi_sync_http_set_response_contents_bin(struct SynchronousHttp *interac * The returned string must be deleted with `pactffi_string_delete`. * * Since it is a copy, the returned string may safely outlive - * the `SynchronousHttp` interaction. + * the `SynchronousMessage`. * * # Errors * @@ -1712,10 +3024,10 @@ void pactffi_sync_http_set_response_contents_bin(struct SynchronousHttp *interac * This function may fail if the Rust string contains embedded * null ('\0') bytes. */ -const char *pactffi_sync_http_get_description(const struct SynchronousHttp *interaction); +const char *pactffi_sync_message_get_description(const struct SynchronousMessage *message); /** - * Write the `description` field on the `SynchronousHttp`. + * Write the `description` field on the `SynchronousMessage`. * * # Safety * @@ -1729,17 +3041,18 @@ const char *pactffi_sync_http_get_description(const struct SynchronousHttp *inte * * Errors will be reported with a non-zero return value. */ -int pactffi_sync_http_set_description(struct SynchronousHttp *interaction, const char *description); +int pactffi_sync_message_set_description(struct SynchronousMessage *message, + const char *description); /** - * Get a copy of the provider state at the given index from this interaction. + * Get a copy of the provider state at the given index from this message. * * # Safety * * The returned structure must be deleted with `provider_state_delete`. * * Since it is a copy, the returned structure may safely outlive - * the `SynchronousHttp`. + * the `SynchronousMessage`. * * # Error Handling * @@ -1748,8 +3061,8 @@ int pactffi_sync_http_set_description(struct SynchronousHttp *interaction, const * This function may fail if the index requested is out of bounds, * or if any of the Rust strings contain embedded null ('\0') bytes. */ -const struct ProviderState *pactffi_sync_http_get_provider_state(const struct SynchronousHttp *interaction, - unsigned int index); +const struct ProviderState *pactffi_sync_message_get_provider_state(const struct SynchronousMessage *message, + unsigned int index); /** * Get an iterator over provider states. @@ -1762,7 +3075,7 @@ const struct ProviderState *pactffi_sync_http_get_provider_state(const struct Sy * * Returns NULL if an error occurs. */ -struct ProviderStateIterator *pactffi_sync_http_get_provider_state_iter(struct SynchronousHttp *interaction); +struct ProviderStateIterator *pactffi_sync_message_get_provider_state_iter(struct SynchronousMessage *message); /** * Delete a string previously returned by this FFI. @@ -2004,7 +3317,16 @@ void pactffi_free_string(char *s); PactHandle pactffi_new_pact(const char *consumer_name, const char *provider_name); /** - * Creates a new HTTP Interaction and returns a handle to it. + * Returns a mutable pointer to a Pact model which has been cloned from the Pact handle's inner + * Pact model. The returned Pact model must be freed with the `pactffi_pact_model_delete` + * function when no longer needed. + */ +struct Pact *pactffi_pact_handle_to_pointer(PactHandle pact); + +/** + * Creates a new HTTP Interaction and returns a handle to it. Calling this function with the + * same description as an existing interaction will result in that interaction being replaced + * with the new one. * * * `description` - The interaction description. It needs to be unique for each interaction. * @@ -2013,7 +3335,10 @@ PactHandle pactffi_new_pact(const char *consumer_name, const char *provider_name InteractionHandle pactffi_new_interaction(PactHandle pact, const char *description); /** - * Creates a new message interaction and return a handle to it + * Creates a new message interaction and returns a handle to it. Calling this function with the + * same description as an existing interaction will result in that interaction being replaced + * with the new one. + * * * `description` - The interaction description. It needs to be unique for each interaction. * * Returns a new `InteractionHandle`. @@ -2021,7 +3346,10 @@ InteractionHandle pactffi_new_interaction(PactHandle pact, const char *descripti InteractionHandle pactffi_new_message_interaction(PactHandle pact, const char *description); /** - * Creates a new synchronous message interaction (request/response) and return a handle to it + * Creates a new synchronous message interaction (request/response) and returns a handle to it. + * Calling this function with the same description as an existing interaction will result in + * that interaction being replaced with the new one. + * * * `description` - The interaction description. It needs to be unique for each interaction. * * Returns a new `InteractionHandle`. @@ -2065,18 +3393,44 @@ unsigned int pactffi_interaction_test_name(InteractionHandle interaction, const char *test_name); /** - * Adds a provider state to the Interaction with a parameter key and value. Returns false if the interaction or Pact can't be - * modified (i.e. the mock server for it has already started) + * Adds a parameter key and value to a provider state to the Interaction. If the provider state + * does not exist, a new one will be created, otherwise the parameter will be merged into the + * existing one. The parameter value will be parsed as JSON. + * + * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has + * already started). * + * # Parameters * * `description` - The provider state description. It needs to be unique. * * `name` - Parameter name. - * * `value` - Parameter value. + * * `value` - Parameter value as JSON. */ bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value); +/** + * Adds a provider state to the Interaction with a set of parameter key and value pairs in JSON + * form. If the params is not an JSON object, it will add it as a single parameter with a `value` + * key. + * + * # Parameters + * * `description` - The provider state description. + * * `params` - Parameter values as a JSON fragment. + * + * # Errors + * Returns EXIT_FAILURE (1) if the interaction or Pact can't be modified (i.e. the mock server + * for it has already started). + * Returns 2 and sets the error message (which can be retrieved with `pactffi_get_error_message`) + * if the parameter values con't be parsed as JSON. + * Returns 3 if any of the C strings are not valid. + * + */ +int pactffi_given_with_params(InteractionHandle interaction, + const char *description, + const char *params); + /** * Configures the request for the Interaction. Returns false if the interaction or Pact can't be * modified (i.e. the mock server for it has already started) @@ -2144,8 +3498,33 @@ bool pactffi_with_query_parameter(InteractionHandle interaction, * ``` * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) * + * If you want the matching rules to apply to all values (and not just the one with the given + * index), make sure to set the value to be an array. + * + * ```c + * const char* value = "{\"value\":[\"2\"], \"pact:matcher:type\":\"regex\", \"regex\":\"\\\\d+\"}"; + * pactffi_with_query_parameter_v2(handle, "id", 0, value); + * ``` + * + * For query parameters with no value, two distinct formats are provided: + * + * 1. Parameters with blank values, as specified by `?foo=&bar=`, require an empty string: + * + * ```c + * pactffi_with_query_parameter_v2(handle, "foo", 0, ""); + * pactffi_with_query_parameter_v2(handle, "bar", 0, ""); + * ``` + * + * 2. Parameters with no associated value, as specified by `?foo&bar`, require a NULL pointer: + * + * ```c + * pactffi_with_query_parameter_v2(handle, "foo", 0, NULL); + * pactffi_with_query_parameter_v2(handle, "bar", 0, NULL); + * ``` + * * # Safety - * The name and value parameters must be valid pointers to NULL terminated strings. + * The name parameter must be a valid pointer to a NULL terminated string. If the value + * parameter is not NULL, it must point to a valid NULL terminated string. * ``` */ bool pactffi_with_query_parameter_v2(InteractionHandle interaction, @@ -2161,7 +3540,12 @@ bool pactffi_with_query_parameter_v2(InteractionHandle interaction, * * `version` - the spec version to use */ bool pactffi_with_specification(PactHandle pact, - enum PactSpecification version); + int version); + +/** + * Returns the Pact specification enum that the Pact is for. + */ +int pactffi_handle_get_pact_spec_version(PactHandle pact); /** * Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version @@ -2177,6 +3561,59 @@ bool pactffi_with_pact_metadata(PactHandle pact, const char *name, const char *value); +/** + * Adds metadata to the interaction. + * + * Metadata is only relevant for message interactions to provide additional + * information about the message, such as the queue name, message type, tags, + * timestamps, etc. + * + * * `key` - metadata key + * * `value` - metadata value, supports JSON structures with matchers and + * generators. Passing a `NULL` point will remove the metadata key instead. + * * `part` - the part of the interaction to add the metadata to (only + * relevant for synchronous message interactions). + * + * Returns `true` if the metadata was added successfully, `false` otherwise. + * + * To include matching rules for the value, include the matching rule JSON + * format with the value as a single JSON document. I.e. + * + * ```c + * const char* value = "{\"value\": { \"ID\": \"sjhdjkshsdjh\", \"weight\": 100.5 }, \"pact:matcher:type\":\"type\"}"; + * pactffi_message_with_metadata_v2(handle, "TagData", value); + * ``` + * + * See + * [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) + * + * # Note + * + * For HTTP interactions, use [`pactffi_with_header_v2`] instead. This + * function will not have any effect on HTTP interactions and returns + * `false`. + * + * For synchronous message interactions, the `part` parameter is required to + * specify whether the metadata should be added to the request or response + * part. For responses which can have multiple messages, the metadata will be + * set on all response messages. This also requires for responses to have + * been defined in the interaction. + * + * The [`pactffi_with_body`] will also contribute to the metadata of the + * message (both sync and async) by setting the key `contentType` with the + * content type of the message. + * + * # Safety + * + * The key and value parameters must be valid pointers to NULL terminated + * strings, or `NULL` for the value parameter if the metadata key should be + * removed. + */ +bool pactffi_with_metadata(InteractionHandle interaction, + const char *key, + const char *value, + int part); + /** * Configures a header for the Interaction. Returns false if the interaction or Pact can't be * modified (i.e. the mock server for it has already started) @@ -2189,7 +3626,7 @@ bool pactffi_with_pact_metadata(PactHandle pact, * **DEPRECATED:** Use `pactffi_with_header_v2`, which deals with multiple values correctly */ bool pactffi_with_header(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *name, size_t index, const char *value); @@ -2227,15 +3664,37 @@ bool pactffi_with_header(InteractionHandle interaction, * ``` * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) * + * NOTE: If you pass in a form with multiple values, the index will be ignored. + * * # Safety * The name and value parameters must be valid pointers to NULL terminated strings. */ bool pactffi_with_header_v2(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *name, size_t index, const char *value); +/** + * Sets a header for the Interaction. Returns false if the interaction or Pact can't be + * modified (i.e. the mock server for it has already started). Note that this function will + * overwrite any previously set header values. Also, this function will not process the value in + * any way, so matching rules and generators can not be configured with it. + * + * If matching rules are required to be set, use `pactffi_with_header_v2`. + * + * * `part` - The part of the interaction to add the header to (Request or Response). + * * `name` - the header name. + * * `value` - the header value. + * + * # Safety + * The name and value parameters must be valid pointers to NULL terminated strings. + */ +bool pactffi_set_header(InteractionHandle interaction, + int part, + const char *name, + const char *value); + /** * Configures the response for the Interaction. Returns false if the interaction or Pact can't be * modified (i.e. the mock server for it has already started) @@ -2244,6 +3703,27 @@ bool pactffi_with_header_v2(InteractionHandle interaction, */ bool pactffi_response_status(InteractionHandle interaction, unsigned short status); +/** + * Configures the response for the Interaction. Returns false if the interaction or Pact can't be + * modified (i.e. the mock server for it has already started) + * + * * `status` - the response status. Defaults to 200. + * + * To include matching rules for the status (only statusCode or integer really makes sense to use), include the + * matching rule JSON format with the value as a single JSON document. I.e. + * + * ```c + * const char* status = "{ \"pact:generator:type\": \"RandomInt\", \"min\": 100, \"max\": 399, \"pact:matcher:type\":\"statusCode\", \"status\": \"nonError\"}"; + * pactffi_response_status_v2(handle, status); + * ``` + * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) + * + * # Safety + * The status parameter must be valid pointers to NULL terminated strings. + */ +bool pactffi_response_status_v2(InteractionHandle interaction, + const char *status); + /** * Adds the body for the interaction. Returns false if the interaction or Pact can't be * modified (i.e. the mock server for it has already started) @@ -2271,10 +3751,46 @@ bool pactffi_response_status(InteractionHandle interaction, unsigned short statu * already started) or an error has occurred. */ bool pactffi_with_body(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *content_type, const char *body); +/** + * Adds the body for the interaction. Returns false if the interaction or Pact can't be + * modified (i.e. the mock server for it has already started) + * + * * `part` - The part of the interaction to add the body to (Request or Response). + * * `content_type` - The content type of the body. Defaults to `application/octet-stream` if it + * is NULL. Will be ignored if a content type header is already set. + * * `body` - Body contents as a pointer to a byte array + * * `size` - Number of bytes in the body + * + * For HTTP and async message interactions, this will overwrite the body. With asynchronous messages, the + * part parameter will be ignored. With synchronous messages, the request contents will be overwritten, + * while a new response will be appended to the message. + * + * # Safety + * + * This function is safe to use as long as the following conditions are true: + * The content type must either be a NULL pointer, or point to valid UTF-8 encoded NULL-terminated + * string. The body pointer must be valid for reads of `size` bytes, and it must be properly + * aligned and consecutive (that just means it must point a continuous array of at least `size` + * bytes that can be read in a single operation and not to non-continuous structures like linked + * lists, etc.). + * + * # Error Handling + * + * If the body is a NULL pointer, it will set the body contents as empty. If the content + * type is a null pointer, it will set the content type as `application/octet-stream`. + * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has + * already started) or an error has occurred. + */ +bool pactffi_with_binary_body(InteractionHandle interaction, + int part, + const char *content_type, + const uint8_t *body, + size_t size); + /** * Adds a binary file as the body with the expected content type and example contents. Will use * a mime type matcher to match the body. Returns false if the interaction or Pact can't be @@ -2303,11 +3819,95 @@ bool pactffi_with_body(InteractionHandle interaction, * already started) or an error has occurred. */ bool pactffi_with_binary_file(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *content_type, const uint8_t *body, size_t size); +/** + * Add matching rules to the interaction. + * + * * `interaction` - Interaction handle to set the matching rules for. + * * `part` - Request or response part (if applicable). + * * `rules` - JSON string of the matching rules to add to the interaction. + * + * This function can be called multiple times, in which case the matching + * rules will be merged. The function will return `true` if the rules were + * successfully added, and `false` if an error occurred. + * + * For synchronous messages which allow multiple responses, the matching + * rules will be added to all the responses. + * + * # Safety + * + * The rules parameter must be a valid pointer to a NULL terminated UTF-8 + * string. + */ +bool pactffi_with_matching_rules(InteractionHandle interaction, + int part, + const char *rules); + +/** + * Add generators to the interaction. + * + * * `interaction` - Interaction handle to set the generators for. + * * `part` - Request or response part (if applicable). + * * `generators` - JSON string of the generators to add to the interaction. + * + * This function can be called multiple times, in which case the generators + * will be combined (provided they don't clash). The function will return + * `true` if the rules were successfully added, and `false` if an error + * occurred. + * + * For synchronous messages which allow multiple responses, the generators + * will be added to all the responses. + * + * # Safety + * + * The generators parameter must be a valid pointer to a NULL terminated + * UTF-8 string. + */ +bool pactffi_with_generators(InteractionHandle interaction, + int part, + const char *generators); + +/** + * Adds a binary file as the body as a MIME multipart with the expected content type and example contents. Will use + * a mime type matcher to match the body. Returns an error if the interaction or Pact can't be + * modified (i.e. the mock server for it has already started) or an error occurs. + * + * * `interaction` - Interaction handle to set the body for. + * * `part` - Request or response part. + * * `content_type` - Expected content type of the file. + * * `file` - path to the example file + * * `part_name` - name for the mime part + * * `boundary` - boundary for the multipart separation + * + * This function can be called multiple times. In that case, each subsequent call will be + * appended to the existing multipart body as a new part. + * + * # Safety + * + * The content type, file path and part name must be valid pointers to UTF-8 encoded NULL-terminated strings. + * Passing invalid pointers or pointers to strings that are not NULL terminated will lead to undefined + * behaviour. + * + * # Error Handling + * + * If the boundary is a NULL pointer, a random string will be used. + * If the file path is a NULL pointer, it will set the body contents as as an empty mime-part. + * If the file path does not point to a valid file, or is not able to be read, it will return an + * error result. If the content type is a null pointer, or can't be parsed, it will return an error result. + * Returns an error if the interaction or Pact can't be modified (i.e. the mock server for it has + * already started), the interaction is not an HTTP interaction or some other error occurs. + */ +struct StringResult pactffi_with_multipart_file_v2(InteractionHandle interaction, + int part, + const char *content_type, + const char *file, + const char *part_name, + const char *boundary); + /** * Adds a binary file as the body as a MIME multipart with the expected content type and example contents. Will use * a mime type matcher to match the body. Returns an error if the interaction or Pact can't be @@ -2319,6 +3919,9 @@ bool pactffi_with_binary_file(InteractionHandle interaction, * * `file` - path to the example file * * `part_name` - name for the mime part * + * This function can be called multiple times. In that case, each subsequent call will be + * appended to the existing multipart body as a new part. + * * # Safety * * The content type, file path and part name must be valid pointers to UTF-8 encoded NULL-terminated strings. @@ -2334,11 +3937,87 @@ bool pactffi_with_binary_file(InteractionHandle interaction, * already started), the interaction is not an HTTP interaction or some other error occurs. */ struct StringResult pactffi_with_multipart_file(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *content_type, const char *file, const char *part_name); +/** + * Sets the key attribute for the interaction. + * + * * `interaction` - Interaction handle to modify. + * * `value` - Key value. This must be a valid UTF-8 null-terminated string, + * or NULL to clear the key. + * + * This function will return `true` if the key was successfully updated. + * + * # Safety + * + * The key parameter must be a valid pointer to a NULL terminated UTF-8, or + * NULL if the key is to be cleared. + */ +bool pactffi_set_key(InteractionHandle interaction, const char *value); + +/** + * Mark the interaction as pending. + * + * * `interaction` - Interaction handle to modify. + * * `pending` - Boolean value to toggle the pending state of the interaction. + * + * This function will return `true` if the key was successfully updated. + */ +bool pactffi_set_pending(InteractionHandle interaction, bool pending); + +/** + * Add a comment to the interaction. + * + * * `interaction` - Interaction handle to set the comments for. + * * `key` - Key value + * * `value` - Comment value. This may be any valid JSON value, or a NULL to + * clear the comment. + * + * This function will return `true` if the comments were successfully + * updated. Both `key` and `value` must be valid UTF-8 null-terminated + * strings; or in the case of `value`, it may also be a NULL pointer in which + * case the comment will be cleared. + * + * Note that a `value` that deserialize to a JSON null will result in a + * comment being added, with the value being the JSON null. + * + * Note that the `text` key is special and is used by + * [`pactffi_add_text_comment`] to append comments to the array of comments. + * Overwriting the `text` key is allowed, but should be done with caution. + * + * # Safety + * + * The comments parameter must be a valid pointer to a NULL terminated UTF-8, + * or NULL if the comment is to be cleared. + */ +bool pactffi_set_comment(InteractionHandle interaction, const char *key, const char *value); + +/** + * Add a text comment to the interaction. + * + * * `interaction` - Interaction handle to set the comments for. + * * `comment` - Comment value. + * + * This function will return `true` if the comments were successfully + * updated. The `comment` must be a valid UTF-8 null-terminated string. + * + * Unlike [`pactffi_set_comment`], this function will always append the + * comment to the array of comments under the `text` key. + * + * If, for any reason, the `text` key is not present or the associated + * value not an array, it will be created as/replaced by an array and the + * comment will be appended to it. + * + * # Safety + * + * The comments parameter must be a valid pointer to a NULL terminated UTF-8, + * or NULL if the comment is to be cleared. + */ +bool pactffi_add_text_comment(InteractionHandle interaction, const char *comment); + /** * Get an iterator over all the messages of the Pact. The returned iterator needs to be * freed with `pactffi_pact_message_iter_delete`. @@ -2356,6 +4035,23 @@ struct StringResult pactffi_with_multipart_file(InteractionHandle interaction, */ struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact); +/** + * Get an iterator over all the asynchronous messages of the Pact. + * The returned iterator needs to be freed with `pactffi_pact_async_message_iter_delete`. + * + * # Safety + * + * The iterator contains a copy of the Pact, so it is always safe to use. + * + * # Error Handling + * + * On failure, this function will return a NULL pointer. + * + * This function may fail if any of the Rust strings contain embedded + * null ('\0') bytes. + */ +struct PactAsyncMessageIterator *pactffi_pact_handle_get_async_message_iter(PactHandle pact); + /** * Get an iterator over all the synchronous request/response messages of the Pact. * The returned iterator needs to be freed with `pactffi_pact_sync_message_iter_delete`. @@ -2466,11 +4162,38 @@ void pactffi_message_with_metadata(MessageHandle message_handle, const char *key, const char *value); +/** + * Adds expected metadata to the Message + * + * * `key` - metadata key + * * `value` - metadata value, supports JSON structures with matchers and generators + * + * To include matching rules for the value, include the + * matching rule JSON format with the value as a single JSON document. I.e. + * + * ```c + * const char* value = "{\"value\": { \"ID\": \"sjhdjkshsdjh\", \"weight\": 100.5 }, \"pact:matcher:type\":\"type\"}"; + * pactffi_message_with_metadata_v2(handle, "TagData", value); + * ``` + * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) + * + * # Safety + * The key and value parameters must be valid pointers to NULL terminated strings. + */ +void pactffi_message_with_metadata_v2(MessageHandle message_handle, + const char *key, + const char *value); + /** * Reifies the given message * * Reification is the process of stripping away any matchers, and returning the original contents. - * NOTE: the returned string needs to be deallocated with the `free_string` function + * + * # Safety + * + * The returned string needs to be deallocated with the `free_string` function. + * This function must only ever be called from a foreign language. Calling it from a Rust function + * that has a Tokio runtime in its call stack can result in a deadlock. */ const char *pactffi_message_reify(MessageHandle message_handle); @@ -2544,6 +4267,9 @@ int32_t pactffi_pact_handle_write_file(PactHandle pact, const char *directory, b * * `description` - The message description. It needs to be unique for each Message. * * Returns a new `MessageHandle`. + * + * Note: This function is deprecated in favour of `new_message_interaction` which returns an + * InteractionHandle that can be used for both HTTP and message interactions. */ MessageHandle pactffi_new_async_message(PactHandle pact, const char *description); @@ -3055,8 +4781,156 @@ void pactffi_cleanup_plugins(PactHandle pact); * When an error errors, LAST_ERROR will contain the error message. */ unsigned int pactffi_interaction_contents(InteractionHandle interaction, - enum InteractionPart part, + int part, const char *content_type, const char *contents); +/** + * Determines if the string value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get as a NULL terminated string + * * actual_value - value to match as a NULL terminated string + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer, and the value parameters must be + * valid pointers to a NULL terminated strings. + */ +const char *pactffi_matches_string_value(const struct MatchingRule *matching_rule, + const char *expected_value, + const char *actual_value, + uint8_t cascaded); + +/** + * Determines if the unsigned integer value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get + * * actual_value - value to match + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer. + */ +const char *pactffi_matches_u64_value(const struct MatchingRule *matching_rule, + uint64_t expected_value, + uint64_t actual_value, + uint8_t cascaded); + +/** + * Determines if the signed integer value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get + * * actual_value - value to match + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer. + */ +const char *pactffi_matches_i64_value(const struct MatchingRule *matching_rule, + int64_t expected_value, + int64_t actual_value, + uint8_t cascaded); + +/** + * Determines if the floating point value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get + * * actual_value - value to match + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer. + */ +const char *pactffi_matches_f64_value(const struct MatchingRule *matching_rule, + double expected_value, + double actual_value, + uint8_t cascaded); + +/** + * Determines if the boolean value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get, 0 == false and 1 == true + * * actual_value - value to match, 0 == false and 1 == true + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer. + */ +const char *pactffi_matches_bool_value(const struct MatchingRule *matching_rule, + uint8_t expected_value, + uint8_t actual_value, + uint8_t cascaded); + +/** + * Determines if the binary value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get + * * expected_value_len - length of the expected value bytes + * * actual_value - value to match + * * actual_value_len - length of the actual value bytes + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule, expected value and actual value pointers must be a valid pointers. + * expected_value_len and actual_value_len must contain the number of bytes that the value + * pointers point to. Passing invalid lengths can lead to undefined behaviour. + */ +const char *pactffi_matches_binary_value(const struct MatchingRule *matching_rule, + const unsigned char *expected_value, + uintptr_t expected_value_len, + const unsigned char *actual_value, + uintptr_t actual_value_len, + uint8_t cascaded); + +/** + * Determines if the JSON value matches the given matching rule. If the value matches OK, + * will return a NULL pointer. If the value does not match, will return a error message as + * a NULL terminated string. The error message pointer will need to be deleted with the + * `pactffi_string_delete` function once it is no longer required. + * + * * matching_rule - pointer to a matching rule + * * expected_value - value we expect to get as a NULL terminated string + * * actual_value - value to match as a NULL terminated string + * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true + * + * # Safety + * + * The matching rule pointer must be a valid pointer, and the value parameters must be + * valid pointers to a NULL terminated strings. + */ +const char *pactffi_matches_json_value(const struct MatchingRule *matching_rule, + const char *expected_value, + const char *actual_value, + uint8_t cascaded); + #endif /* pact_ffi_h */ diff --git a/internal/native/verifier.go b/internal/native/verifier.go index 8fc948c4b..26d41fd53 100644 --- a/internal/native/verifier.go +++ b/internal/native/verifier.go @@ -1,38 +1,7 @@ package native /* -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -char* pactffi_version(); -void pactffi_free_string(char* s); -int pactffi_verify(char* s); - -typedef struct VerifierHandle VerifierHandle; -struct VerifierHandle { - -}; -VerifierHandle *pactffi_verifier_new_for_application(const char *name, const char *version); -void pactffi_verifier_shutdown(struct VerifierHandle *handle); -void pactffi_verifier_set_provider_info(VerifierHandle *handle, const char *name, const char *scheme, const char *host, uint32_t port, const char *path); -void pactffi_verifier_set_filter_info(VerifierHandle *handle, const char *filter_description, const char *filter_state, bool filter_no_state); -void pactffi_verifier_set_provider_state(VerifierHandle *handle, const char *url, bool teardown, bool body); -int pactffi_verifier_set_verification_options(VerifierHandle *handle, bool disable_ssl_verification, unsigned long request_timeout); -int pactffi_verifier_set_publish_options(VerifierHandle *handle, const char *provider_version, const char *build_url, const char *const *provider_tags, uint32_t provider_tags_len, const char *provider_branch); -void pactffi_verifier_set_consumer_filters(VerifierHandle *handle, const char *const *consumer_filters, uint32_t consumer_filters_len); -void pactffi_verifier_add_custom_header(VerifierHandle *handle, const char *header_name, const char *header_value); -void pactffi_verifier_add_file_source(VerifierHandle *handle, const char *file); -void pactffi_verifier_add_directory_source(VerifierHandle *handle, const char *directory); -void pactffi_verifier_url_source(VerifierHandle *handle, const char *url, const char *username, const char *password, const char *token); -void pactffi_verifier_broker_source_with_selectors(VerifierHandle *handle, const char *url, const char *username, const char *password, const char *token, bool enable_pending, const char *include_wip_pacts_since, const char *const *provider_tags, uint32_t provider_tags_len, const char *provider_branch, const char *const *consumer_version_selectors, uint32_t consumer_version_selectors_len, const char *const *consumer_version_tags, uint32_t consumer_version_tags_len); -int pactffi_verifier_execute(VerifierHandle *handle); -void pactffi_verifier_add_provider_transport(VerifierHandle *handle, const char *protocol, uint32_t port, const char *path, const char *scheme); -void pactffi_verifier_set_no_pacts_is_error(VerifierHandle *handle, bool is_error); -int pactffi_verifier_set_coloured_output(struct VerifierHandle *handle, bool coloured_output); +#include "pact.h" */ import "C" @@ -114,7 +83,7 @@ func (v *Verifier) SetProviderInfo(name string, scheme string, host string, port defer free(cScheme) cHost := C.CString(host) defer free(cHost) - cPort := C.uint(port) + cPort := C.ushort(port) cPath := C.CString(path) defer free(cPath) @@ -125,7 +94,7 @@ func (v *Verifier) AddTransport(protocol string, port uint16, path string, schem log.Println("[DEBUG] Adding transport with protocol:", protocol, "port:", port, "path:", path, "scheme:", scheme) cProtocol := C.CString(protocol) defer free(cProtocol) - cPort := C.uint(port) + cPort := C.ushort(port) cPath := C.CString(path) defer free(cPath) cScheme := C.CString(scheme) @@ -140,24 +109,24 @@ func (v *Verifier) SetFilterInfo(description string, state string, noState bool) cFilterState := C.CString(state) defer free(cFilterState) - C.pactffi_verifier_set_filter_info(v.handle, cFilterDescription, cFilterState, boolToCInt(noState)) + C.pactffi_verifier_set_filter_info(v.handle, cFilterDescription, cFilterState, boolToCUchar(noState)) } func (v *Verifier) SetProviderState(url string, teardown bool, body bool) { cURL := C.CString(url) defer free(cURL) - C.pactffi_verifier_set_provider_state(v.handle, cURL, boolToCInt(teardown), boolToCInt(body)) + C.pactffi_verifier_set_provider_state(v.handle, cURL, boolToCUchar(teardown), boolToCUchar(body)) } func (v *Verifier) SetVerificationOptions(disableSSLVerification bool, requestTimeout int64) { // TODO: this returns an int and therefore can error. We should have all of these functions return values?? - C.pactffi_verifier_set_verification_options(v.handle, boolToCInt(disableSSLVerification), C.ulong(requestTimeout)) + C.pactffi_verifier_set_verification_options(v.handle, boolToCUchar(disableSSLVerification), C.ulong(requestTimeout)) } func (v *Verifier) SetConsumerFilters(consumers []string) { // TODO: check if this actually works! - C.pactffi_verifier_set_consumer_filters(v.handle, stringArrayToCStringArray(consumers), C.uint(len(consumers))) + C.pactffi_verifier_set_consumer_filters(v.handle, stringArrayToCStringArray(consumers), C.ushort(len(consumers))) } func (v *Verifier) AddCustomHeader(name string, value string) { @@ -210,7 +179,7 @@ func (v *Verifier) BrokerSourceWithSelectors(url string, username string, passwo cProviderBranch := C.CString(providerBranch) defer free(cProviderBranch) - C.pactffi_verifier_broker_source_with_selectors(v.handle, cUrl, cUsername, cPassword, cToken, boolToCInt(enablePending), cIncludeWipPactsSince, stringArrayToCStringArray(providerTags), C.uint(len(providerTags)), cProviderBranch, stringArrayToCStringArray(selectors), C.uint(len(selectors)), stringArrayToCStringArray(consumerVersionTags), C.uint(len(consumerVersionTags))) + C.pactffi_verifier_broker_source_with_selectors(v.handle, cUrl, cUsername, cPassword, cToken, boolToCUchar(enablePending), cIncludeWipPactsSince, stringArrayToCStringArray(providerTags), C.ushort(len(providerTags)), cProviderBranch, stringArrayToCStringArray(selectors), C.ushort(len(selectors)), stringArrayToCStringArray(consumerVersionTags), C.ushort(len(consumerVersionTags))) } func (v *Verifier) SetPublishOptions(providerVersion string, buildUrl string, providerTags []string, providerBranch string) { @@ -221,7 +190,7 @@ func (v *Verifier) SetPublishOptions(providerVersion string, buildUrl string, pr cProviderBranch := C.CString(providerBranch) defer free(cProviderBranch) - C.pactffi_verifier_set_publish_options(v.handle, cProviderVersion, cBuildUrl, stringArrayToCStringArray(providerTags), C.uint(len(providerTags)), cProviderBranch) + C.pactffi_verifier_set_publish_options(v.handle, cProviderVersion, cBuildUrl, stringArrayToCStringArray(providerTags), C.ushort(len(providerTags)), cProviderBranch) } func (v *Verifier) Execute() error { @@ -245,11 +214,11 @@ func (v *Verifier) Execute() error { } func (v *Verifier) SetNoPactsIsError(isError bool) { - C.pactffi_verifier_set_no_pacts_is_error(v.handle, boolToCInt(isError)) + C.pactffi_verifier_set_no_pacts_is_error(v.handle, boolToCUchar(isError)) } func (v *Verifier) SetColoredOutput(isColoredOutput bool) { - C.pactffi_verifier_set_coloured_output(v.handle, boolToCInt(isColoredOutput)) + C.pactffi_verifier_set_coloured_output(v.handle, boolToCUchar(isColoredOutput)) } func stringArrayToCStringArray(inputs []string) **C.char { @@ -266,9 +235,9 @@ func stringArrayToCStringArray(inputs []string) **C.char { return (**C.char)(unsafe.Pointer(&output[0])) } -func boolToCInt(val bool) C.int { +func boolToCUchar(val bool) C.uchar { if val { - return C.int(1) + return C.uchar(1) } - return C.int(0) + return C.uchar(0) }