diff --git a/code/logic/CMakeLists.txt b/code/logic/CMakeLists.txt index 89620bf..fded761 100644 --- a/code/logic/CMakeLists.txt +++ b/code/logic/CMakeLists.txt @@ -17,6 +17,7 @@ set(TEST_CODE stream.c keyboard.c network.c + cstring.c ) # Create the library target diff --git a/code/logic/cstring.c b/code/logic/cstring.c new file mode 100644 index 0000000..059f49e --- /dev/null +++ b/code/logic/cstring.c @@ -0,0 +1,390 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/io/cstring.h" +#include +#include + +// ============================================================================ +// C String Functions +// ============================================================================ + +cstring fossil_io_cstring_create(const char *init) { + if (!init) return NULL; + size_t length = strlen(init); + cstring str = (cstring)malloc(length + 1); + if (str) { + strcpy(str, init); + } + return str; +} + +void fossil_io_cstring_free(cstring str) { + if (str) { + free(str); + } +} + +cstring fossil_io_cstring_copy(ccstring str) { + if (!str) return NULL; + return fossil_io_cstring_create(str); +} + +cstring fossil_io_cstring_dup(ccstring str) { + if (!str) return NULL; + size_t length = strlen(str); + cstring new_str = (cstring)malloc(length + 1); + if (new_str) { + strcpy(new_str, str); + } + return new_str; +} + +cstring fossil_io_cstring_concat(ccstring s1, ccstring s2) { + if (!s1 || !s2) return NULL; + size_t length1 = strlen(s1); + size_t length2 = strlen(s2); + cstring str = (cstring)malloc(length1 + length2 + 1); + if (str) { + strcpy(str, s1); + strcpy(str + length1, s2); + } + return str; +} + +size_t fossil_io_cstring_length(ccstring str) { + if (!str) return 0; + return strlen(str); +} + +int fossil_io_cstring_compare(ccstring s1, ccstring s2) { + if (!s1 || !s2) return -1; + return strcmp(s1, s2); +} + +void fossil_io_cstring_trim(cstring str) { + if (!str) return; + size_t length = strlen(str); + size_t start = 0; + size_t end = length - 1; + while (start < length && isspace(str[start])) { + start++; + } + while (end > start && isspace(str[end])) { + end--; + } + size_t count = end - start + 1; + if (start > 0) { + memmove(str, str + start, count); + } + str[count] = '\0'; +} + +cstring *fossil_io_cstring_split(ccstring str, char delimiter, size_t *count) { + if (!str || !count) return NULL; + size_t length = strlen(str); + size_t num_delimiters = 0; + for (size_t i = 0; i < length; i++) { + if (str[i] == delimiter) { + num_delimiters++; + } + } + *count = num_delimiters + 1; + cstring *result = (cstring*)malloc(*count * sizeof(cstring)); + if (result) { + size_t start = 0; + size_t index = 0; + for (size_t i = 0; i < length; i++) { + if (str[i] == delimiter) { + size_t count = i - start; + result[index] = (cstring)malloc(count + 1); + if (result[index]) { + memcpy(result[index], str + start, count); + result[index][count] = '\0'; + start = i + 1; + index++; + } else { + // Free previously allocated memory on error + for (size_t j = 0; j < index; j++) { + free(result[j]); + } + free(result); + return NULL; + } + } + } + size_t count = length - start; + result[index] = (cstring)malloc(count + 1); + if (result[index]) { + memcpy(result[index], str + start, count); + result[index][count] = '\0'; + } else { + // Free previously allocated memory on error + for (size_t j = 0; j < index; j++) { + free(result[j]); + } + free(result); + return NULL; + } + } + return result; +} + +cstring fossil_io_cstring_replace(ccstring str, ccstring old, ccstring new_str) { + if (!str || !old || !new_str) return NULL; + size_t old_length = strlen(old); + size_t new_length = strlen(new_str); + size_t count = 0; + size_t index = 0; + size_t length = strlen(str); + while (index < length) { + if (strstr(str + index, old) == str + index) { + count++; + index += old_length; + } else { + index++; + } + } + cstring result = (cstring)malloc(length + count * (new_length - old_length) + 1); + if (result) { + index = 0; + size_t start = 0; + while (index < length) { + if (strstr(str + index, old) == str + index) { + strcpy(result + start, new_str); + start += new_length; + index += old_length; + } else { + result[start] = str[index]; + start++; + index++; + } + } + result[start] = '\0'; + } + return result; +} + +cstring fossil_io_cstring_to_upper(cstring str) { + if (!str) return NULL; + size_t length = strlen(str); + cstring result = (cstring)malloc(length + 1); + if (result) { + for (size_t i = 0; i < length; i++) { + result[i] = toupper(str[i]); + } + result[length] = '\0'; + } + return result; +} + +cstring fossil_io_cstring_to_lower(cstring str) { + if (!str) return NULL; + size_t length = strlen(str); + cstring result = (cstring)malloc(length + 1); + if (result) { + for (size_t i = 0; i < length; i++) { + result[i] = tolower(str[i]); + } + result[length] = '\0'; + } + return result; +} + +int fossil_io_cstring_starts_with(ccstring str, ccstring prefix) { + if (!str || !prefix) return 0; + size_t str_length = strlen(str); + size_t prefix_length = strlen(prefix); + if (prefix_length > str_length) { + return 0; + } + return strncmp(str, prefix, prefix_length) == 0; +} + +int fossil_io_cstring_ends_with(ccstring str, ccstring suffix) { + if (!str || !suffix) return 0; + size_t str_length = strlen(str); + size_t suffix_length = strlen(suffix); + if (suffix_length > str_length) { + return 0; + } + return strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0; +} + +cstring fossil_io_cstring_substring(ccstring str, size_t start, size_t length) { + if (!str) return NULL; + size_t str_length = strlen(str); + if (start >= str_length) { + return NULL; + } + cstring result = (cstring)malloc(length + 1); + if (result) { + size_t count = str_length - start; + if (length < count) { + count = length; + } + memcpy(result, str + start, count); + result[count] = '\0'; + } + return result; +} + +cstring fossil_io_cstring_reverse(cstring str) { + if (!str) return NULL; + size_t length = strlen(str); + cstring result = (cstring)malloc(length + 1); + if (result) { + for (size_t i = 0; i < length; i++) { + result[i] = str[length - i - 1]; + } + result[length] = '\0'; + } + return result; +} + +int fossil_io_cstring_contains(ccstring str, ccstring substr) { + if (!str || !substr) return 0; + return strstr(str, substr) != NULL; +} + +cstring fossil_io_cstring_repeat(ccstring str, size_t count) { + if (!str || count == 0) return NULL; + size_t length = strlen(str); + size_t new_length = length * count; + cstring result = (cstring)malloc(new_length + 1); + if (result) { + for (size_t i = 0; i < count; i++) { + memcpy(result + i * length, str, length); + } + result[new_length] = '\0'; + } + return result; +} + +cstring fossil_io_cstring_strip(ccstring str, char ch) { + if (!str) return NULL; + size_t length = strlen(str); + size_t start = 0; + size_t end = length - 1; + while (start < length && str[start] == ch) { + start++; + } + while (end > start && str[end] == ch) { + end--; + } + size_t count = end - start + 1; + cstring result = (cstring)malloc(count + 1); + if (result) { + memcpy(result, str + start, count); + result[count] = '\0'; + } + return result; +} + +size_t fossil_io_cstring_count(ccstring str, ccstring substr) { + if (!str || !substr) return 0; + size_t count = 0; + size_t length = strlen(substr); + while ((str = strstr(str, substr)) != NULL) { + count++; + str += length; + } + return count; +} + +cstring fossil_io_cstring_pad_left(ccstring str, size_t total_length, char pad_char) { + if (!str || total_length == 0) return NULL; + size_t length = strlen(str); + if (length >= total_length) { + return fossil_io_cstring_copy(str); + } + size_t pad_length = total_length - length; + cstring result = (cstring)malloc(total_length + 1); + if (result) { + memset(result, pad_char, pad_length); + strcpy(result + pad_length, str); + result[total_length] = '\0'; + } + return result; +} + +cstring fossil_io_cstring_pad_right(ccstring str, size_t total_length, char pad_char) { + if (!str || total_length == 0) return NULL; + size_t length = strlen(str); + if (length >= total_length) { + return fossil_io_cstring_copy(str); + } + size_t pad_length = total_length - length; + cstring result = (cstring)malloc(total_length + 1); + if (result) { + strcpy(result, str); + memset(result + length, pad_char, pad_length); + result[total_length] = '\0'; + } + return result; +} + +// ============================================================================ +// String Stream Functions +// ============================================================================ + +fossil_io_cstring_stream* fossil_io_cstring_stream_create(size_t initial_size) { + if (initial_size == 0) return NULL; + fossil_io_cstring_stream *stream = (fossil_io_cstring_stream*)malloc(sizeof(fossil_io_cstring_stream)); + if (stream) { + stream->buffer = (char*)malloc(initial_size); + if (stream->buffer) { + stream->buffer[0] = '\0'; + stream->length = 0; + stream->capacity = initial_size; + } else { + free(stream); + stream = NULL; + } + } + return stream; +} + +void fossil_io_cstring_stream_free(fossil_io_cstring_stream *stream) { + if (stream) { + free(stream->buffer); + free(stream); + } +} + +void fossil_io_cstring_stream_write(fossil_io_cstring_stream *stream, ccstring str) { + if (!stream || !str) return; + size_t length = strlen(str); + size_t new_length = stream->length + length; + if (new_length > stream->capacity) { + size_t new_capacity = stream->capacity * 2; + if (new_capacity < new_length) { + new_capacity = new_length; + } + char *new_buffer = (char*)realloc(stream->buffer, new_capacity); + if (new_buffer) { + stream->buffer = new_buffer; + stream->capacity = new_capacity; + } else { + return; + } + } + memcpy(stream->buffer + stream->length, str, length); + stream->length = new_length; + stream->buffer[stream->length] = '\0'; +} + +ccstring fossil_io_cstring_stream_read(fossil_io_cstring_stream *stream) { + if (!stream) return NULL; + return stream->buffer; +} diff --git a/code/logic/fossil/io/cstring.h b/code/logic/fossil/io/cstring.h new file mode 100644 index 0000000..e6274ba --- /dev/null +++ b/code/logic/fossil/io/cstring.h @@ -0,0 +1,557 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_IO_CSTRING_H +#define FOSSIL_IO_CSTRING_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Type definitions */ +typedef char* cstring; +typedef const char* ccstring; + +typedef struct { + char *buffer; + size_t length; + size_t capacity; +} fossil_io_cstring_stream; + +/** + * @brief Creates a new cstring with the given initial value. + * + * @param init The initial value for the cstring. + * @return A new cstring initialized with the given value. + */ +cstring fossil_io_cstring_create(const char *init); + +/** + * @brief Frees the memory allocated for the given cstring. + * + * @param str The cstring to be freed. + */ +void fossil_io_cstring_free(cstring str); + +/** + * @brief Creates a copy of the given cstring. + * + * @param str The cstring to be copied. + * @return A new cstring that is a copy of the given cstring. + */ +cstring fossil_io_cstring_copy(ccstring str); + +/** + * @brief Duplicates the given cstring. + * + * @param str The cstring to be duplicated. + * @return A new cstring that is a duplicate of the given cstring. + */ +cstring fossil_io_cstring_dup(ccstring str); + +/** + * @brief Concatenates two cstrings into a new cstring. + * + * @param s1 The first cstring. + * @param s2 The second cstring. + * @return A new cstring that is the concatenation of s1 and s2. + */ +cstring fossil_io_cstring_concat(ccstring s1, ccstring s2); + +/** + * @brief Returns the length of the given cstring. + * + * @param str The cstring whose length is to be determined. + * @return The length of the given cstring. + */ +size_t fossil_io_cstring_length(ccstring str); + +/** + * @brief Compares two cstrings. + * + * @param s1 The first cstring. + * @param s2 The second cstring. + * @return An integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2. + */ +int fossil_io_cstring_compare(ccstring s1, ccstring s2); + +/** + * @brief Trims whitespace from the beginning and end of the given cstring. + * + * @param str The cstring to be trimmed. + */ +void fossil_io_cstring_trim(cstring str); + +/** + * @brief Splits the given cstring by the specified delimiter. + * + * @param str The cstring to be split. + * @param delimiter The character to split the cstring by. + * @param count Pointer to a size_t variable where the number of resulting substrings will be stored. + * @return An array of cstrings resulting from the split operation. + */ +cstring *fossil_io_cstring_split(ccstring str, char delimiter, size_t *count); + +/** + * @brief Replaces all occurrences of a substring within a cstring with another substring. + * + * @param str The original cstring. + * @param old The substring to be replaced. + * @param new_str The substring to replace with. + * @return A new cstring with the replacements made. + */ +cstring fossil_io_cstring_replace(ccstring str, ccstring old, ccstring new_str); + +/** + * @brief Converts all characters in the given cstring to uppercase. + * + * @param str The cstring to be converted. + * @return The cstring with all characters converted to uppercase. + */ +cstring fossil_io_cstring_to_upper(cstring str); + +/** + * @brief Converts all characters in the given cstring to lowercase. + * + * @param str The cstring to be converted. + * @return The cstring with all characters converted to lowercase. + */ +cstring fossil_io_cstring_to_lower(cstring str); + +/** + * @brief Checks if the given cstring starts with the specified prefix. + * + * @param str The cstring to be checked. + * @param prefix The prefix to check for. + * @return 1 if the cstring starts with the prefix, 0 otherwise. + */ +int fossil_io_cstring_starts_with(ccstring str, ccstring prefix); + +/** + * @brief Checks if the given cstring ends with the specified suffix. + * + * @param str The cstring to be checked. + * @param suffix The suffix to check for. + * @return 1 if the cstring ends with the suffix, 0 otherwise. + */ +int fossil_io_cstring_ends_with(ccstring str, ccstring suffix); + +/** + * @brief Extracts a substring from the given cstring. + * + * @param str The original cstring. + * @param start The starting index of the substring. + * @param length The length of the substring. + * @return A new cstring that is the specified substring of the original cstring. + */ +cstring fossil_io_cstring_substring(ccstring str, size_t start, size_t length); + +/** + * @brief Reverses the given cstring. + * + * @param str The cstring to be reversed. + * @return A new cstring that is the reverse of the given cstring. + */ +cstring fossil_io_cstring_reverse(cstring str); + +/** + * @brief Checks if the given cstring contains the specified substring. + * + * @param str The cstring to be checked. + * @param substr The substring to check for. + * @return 1 if the cstring contains the substring, 0 otherwise. + */ +int fossil_io_cstring_contains(ccstring str, ccstring substr); + +/** + * @brief Repeats the given cstring the specified number of times. + * + * @param str The cstring to be repeated. + * @param count The number of times to repeat the cstring. + * @return A new cstring that is the original cstring repeated the specified number of times. + */ +cstring fossil_io_cstring_repeat(ccstring str, size_t count); + +/** + * @brief Strips the given character from the beginning and end of the cstring. + * + * @param str The cstring to be stripped. + * @param ch The character to strip. + * @return A new cstring that is the original cstring with the specified character stripped from the beginning and end. + */ +cstring fossil_io_cstring_strip(ccstring str, char ch); + +/** + * @brief Counts the number of occurrences of a substring within the given cstring. + * + * @param str The cstring to be searched. + * @param substr The substring to search for. + * @return The number of occurrences of the substring within the cstring. + */ +size_t fossil_io_cstring_count(ccstring str, ccstring substr); + +/** + * @brief Pads the given cstring with the specified character on the left side. + * + * @param str The cstring to be padded. + * @param total_length The total length of the resulting cstring. + * @param pad_char The character to pad with. + * @return A new cstring that is the original cstring padded on the left side. + */ +cstring fossil_io_cstring_pad_left(ccstring str, size_t total_length, char pad_char); + +/** + * @brief Pads the given cstring with the specified character on the right side. + * + * @param str The cstring to be padded. + * @param total_length The total length of the resulting cstring. + * @param pad_char The character to pad with. + * @return A new cstring that is the original cstring padded on the right side. + */ +cstring fossil_io_cstring_pad_right(ccstring str, size_t total_length, char pad_char); + +/** + * @brief Creates a new cstring stream with the specified initial size. + * + * @param initial_size The initial size of the cstring stream. + * @return A pointer to the newly created cstring stream. + */ +fossil_io_cstring_stream* fossil_io_cstring_stream_create(size_t initial_size); + +/** + * @brief Frees the memory allocated for the given cstring stream. + * + * @param stream The cstring stream to be freed. + */ +void fossil_io_cstring_stream_free(fossil_io_cstring_stream *stream); + +/** + * @brief Writes a cstring to the given cstring stream. + * + * @param stream The cstring stream to write to. + * @param str The cstring to be written. + */ +void fossil_io_cstring_stream_write(fossil_io_cstring_stream *stream, ccstring str); + +/** + * @brief Reads the contents of the given cstring stream. + * + * @param stream The cstring stream to read from. + * @return The contents of the cstring stream as a cstring. + */ +ccstring fossil_io_cstring_stream_read(fossil_io_cstring_stream *stream); + +#ifdef __cplusplus +} + +#include +#include + +/** + * namespace for Fossil Logic. + */ +namespace fossil { + + /** + * Namespace for I/O operations. + */ + namespace io { + + class CString { + private: + cstring _str; + + public: + /** + * Constructor to create a new cstring with the given initial value. + * + * @param init The initial value for the cstring. + */ + CString(const std::string &init) { + _str = fossil_io_cstring_create(init.c_str()); + } + + /** + * Destructor to free the memory allocated for the cstring. + */ + ~CString() { + fossil_io_cstring_free(_str); + } + + /** + * Creates a copy of the given cstring. + * + * @param str The cstring to be copied. + * @return A new CString that is a copy of the given cstring. + */ + static CString copy(const std::string &str) { + return CString(fossil_io_cstring_copy(str.c_str())); + } + + /** + * Duplicates the given cstring. + * + * @param str The cstring to be duplicated. + * @return A new CString that is a duplicate of the given cstring. + */ + static CString dup(const std::string &str) { + return CString(fossil_io_cstring_dup(str.c_str())); + } + + /** + * Concatenates two cstrings into a new CString. + * + * @param s1 The first cstring. + * @param s2 The second cstring. + * @return A new CString that is the concatenation of s1 and s2. + */ + static CString concat(const std::string &s1, const std::string &s2) { + return CString(fossil_io_cstring_concat(s1.c_str(), s2.c_str())); + } + + /** + * Returns the length of the cstring. + * + * @return The length of the cstring. + */ + size_t length() const { + return fossil_io_cstring_length(_str); + } + + /** + * Compares this cstring with another cstring. + * + * @param other The other cstring to compare with. + * @return An integer less than, equal to, or greater than zero if this cstring is found, respectively, to be less than, to match, or be greater than the other cstring. + */ + int compare(const std::string &other) const { + return fossil_io_cstring_compare(_str, other.c_str()); + } + + /** + * Trims whitespace from the beginning and end of the cstring. + */ + void trim() { + fossil_io_cstring_trim(_str); + } + + /** + * Splits the cstring by the specified delimiter. + * + * @param delimiter The character to split the cstring by. + * @param count Pointer to a size_t variable where the number of resulting substrings will be stored. + * @return An array of cstrings resulting from the split operation. + */ + std::vector split(char delimiter, size_t *count) const { + cstring *result = fossil_io_cstring_split(_str, delimiter, count); + std::vector vec; + for (size_t i = 0; i < *count; i++) { + vec.push_back(result[i]); + } + return vec; + } + + /** + * Replaces all occurrences of a substring within the cstring with another substring. + * + * @param old The substring to be replaced. + * @param new_str The substring to replace with. + * @return A new CString with the replacements made. + */ + CString replace(const std::string &old, const std::string &new_str) const { + return CString(fossil_io_cstring_replace(_str, old.c_str(), new_str.c_str())); + } + + /** + * Converts all characters in the cstring to uppercase. + * + * @return The cstring with all characters converted to uppercase. + */ + CString to_upper() const { + return CString(fossil_io_cstring_to_upper(_str)); + } + + /** + * Converts all characters in the cstring to lowercase. + * + * @return The cstring with all characters converted to lowercase. + */ + CString to_lower() const { + return CString(fossil_io_cstring_to_lower(_str)); + } + + /** + * Checks if the cstring starts with the specified prefix. + * + * @param prefix The prefix to check for. + * @return True if the cstring starts with the prefix, false otherwise. + */ + bool starts_with(const std::string &prefix) const { + return fossil_io_cstring_starts_with(_str, prefix.c_str()); + } + + /** + * Checks if the cstring ends with the specified suffix. + * + * @param suffix The suffix to check for. + * @return True if the cstring ends with the suffix, false otherwise. + */ + bool ends_with(const std::string &suffix) const { + return fossil_io_cstring_ends_with(_str, suffix.c_str()); + } + + /** + * Extracts a substring from the cstring. + * + * @param start The starting index of the substring. + * @param length The length of the substring. + * @return A new CString that is the specified substring of the original cstring. + */ + CString substring(size_t start, size_t length) const { + return CString(fossil_io_cstring_substring(_str, start, length)); + } + + /** + * Reverses the cstring. + * + * @return A new CString that is the reverse of the cstring. + */ + CString reverse() const { + return CString(fossil_io_cstring_reverse(_str)); + } + + /** + * Checks if the cstring contains the specified substring. + * + * @param substr The substring to check for. + * @return True if the cstring contains the substring, false otherwise. + */ + bool contains(const std::string &substr) const { + return fossil_io_cstring_contains(_str, substr.c_str()); + } + + /** + * Repeats the cstring the specified number of times. + * + * @param count The number of times to repeat the cstring. + * @return A new CString that is the original cstring repeated the specified number of times. + */ + CString repeat(size_t count) const { + return CString(fossil_io_cstring_repeat(_str, count)); + } + + /** + * Strips the given character from the beginning and end of the cstring. + * + * @param ch The character to strip. + * @return A new CString that is the original cstring with the specified character stripped from the beginning and end. + */ + CString strip(char ch) const { + return CString(fossil_io_cstring_strip(_str, ch)); + } + + /** + * Counts the number of occurrences of a substring within the cstring. + * + * @param substr The substring to search for. + * @return The number of occurrences of the substring within the cstring. + */ + size_t count(const std::string &substr) const { + return fossil_io_cstring_count(_str, substr.c_str()); + } + + /** + * Pads the cstring with the specified character on the left side. + * + * @param total_length The total length of the resulting cstring. + * @param pad_char The character to pad with. + * @return A new CString that is the original cstring padded on the left side. + */ + CString pad_left(size_t total_length, char pad_char) const { + return CString(fossil_io_cstring_pad_left(_str, total_length, pad_char)); + } + + /** + * Pads the cstring with the specified character on the right side. + * + * @param total_length The total length of the resulting cstring. + * @param pad_char The character to pad with. + * @return A new CString that is the original cstring padded on the right side. + */ + CString pad_right(size_t total_length, char pad_char) const { + return CString(fossil_io_cstring_pad_right(_str, total_length, pad_char)); + } + + /** + * Returns the underlying cstring. + * + * @return The underlying cstring. + */ + cstring str() const { + return _str; + } + }; + + class CStringStream { + private: + fossil_io_cstring_stream* _stream; + + public: + /** + * Constructor to create a new cstring stream with the specified initial size. + * + * @param initial_size The initial size of the cstring stream. + */ + CStringStream(size_t initial_size) { + _stream = fossil_io_cstring_stream_create(initial_size); + } + + /** + * Destructor to free the memory allocated for the cstring stream. + */ + ~CStringStream() { + fossil_io_cstring_stream_free(_stream); + } + + /** + * Writes a cstring to the cstring stream. + * + * @param str The cstring to be written. + */ + void write(const std::string &str) { + fossil_io_cstring_stream_write(_stream, str.c_str()); + } + + /** + * Reads the contents of the cstring stream. + * + * @return The contents of the cstring stream as a cstring. + */ + std::string read() const { + return fossil_io_cstring_stream_read(_stream); + } + + }; + + } + +} + +#endif + +#endif /* FOSSIL_IO_FRAMEWORK_H */ diff --git a/code/logic/fossil/io/framework.h b/code/logic/fossil/io/framework.h index 8492f42..f834fc2 100644 --- a/code/logic/fossil/io/framework.h +++ b/code/logic/fossil/io/framework.h @@ -21,6 +21,7 @@ #include "output.h" #include "input.h" #include "error.h" +#include "cstring.h" #include "stream.h" #include "soap.h" #include "parser.h" diff --git a/code/logic/meson.build b/code/logic/meson.build index 94bf05d..2c266c3 100644 --- a/code/logic/meson.build +++ b/code/logic/meson.build @@ -9,7 +9,7 @@ else endif fossil_io_lib = library('fossil-io', - files('serialize.c', 'parser.c', 'input.c', 'output.c', 'error.c', 'soap.c', 'stream.c', 'keyboard.c', 'network.c'), + files('serialize.c', 'parser.c', 'input.c', 'output.c', 'error.c', 'soap.c', 'stream.c', 'keyboard.c', 'network.c', 'cstring.c'), install: true, dependencies: [cc.find_library('m', required: false), winsock_dep], include_directories: dir) diff --git a/code/tests/cases/test_cstring.c b/code/tests/cases/test_cstring.c new file mode 100644 index 0000000..6ca7959 --- /dev/null +++ b/code/tests/cases/test_cstring.c @@ -0,0 +1,279 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include + +#include "fossil/io/framework.h" + + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Utilites +// * * * * * * * * * * * * * * * * * * * * * * * * +// Setup steps for things like test fixtures and +// mock objects are set here. +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Define the test suite and add test cases +FOSSIL_TEST_SUITE(c_string_suite); +fossil_fstream_t c_string; + +// Setup function for the test suite +FOSSIL_SETUP(c_string_suite) { + // Setup code here +} + +// Teardown function for the test suite +FOSSIL_TEARDOWN(c_string_suite) { + // Teardown code here +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Cases +// * * * * * * * * * * * * * * * * * * * * * * * * +// The test cases below are provided as samples, inspired +// by the Meson build system's approach of using test cases +// as samples for library usage. +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_CASE(c_test_cstring_create_and_free) { + const char *init = "Hello, World!"; + cstring str = fossil_io_cstring_create(init); + ASSUME_NOT_CNULL(str); + ASSUME_ITS_EQUAL_CSTR(init, str); + fossil_io_cstring_free(str); +} + +FOSSIL_TEST_CASE(c_test_cstring_copy) { + const char *init = "Hello, World!"; + cstring str = fossil_io_cstring_create(init); + cstring copy = fossil_io_cstring_copy(str); + ASSUME_NOT_CNULL(copy); + ASSUME_ITS_EQUAL_CSTR(init, copy); + fossil_io_cstring_free(str); + fossil_io_cstring_free(copy); +} + +FOSSIL_TEST_CASE(c_test_cstring_concat) { + const char *s1 = "Hello, "; + const char *s2 = "World!"; + cstring result = fossil_io_cstring_concat(s1, s2); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_length) { + const char *str = "Hello, World!"; + size_t length = fossil_io_cstring_length(str); + ASSUME_ITS_EQUAL_SIZE(strlen(str), length); +} + +FOSSIL_TEST_CASE(c_test_cstring_compare) { + const char *s1 = "Hello"; + const char *s2 = "Hello"; + const char *s3 = "World"; + ASSUME_ITS_EQUAL_I32(0, fossil_io_cstring_compare(s1, s2)); + ASSUME_ITS_TRUE(fossil_io_cstring_compare(s1, s3) < 0); + ASSUME_ITS_TRUE(fossil_io_cstring_compare(s3, s1) > 0); +} + +FOSSIL_TEST_CASE(c_test_cstring_trim) { + cstring str = fossil_io_cstring_create(" Hello, World! "); + fossil_io_cstring_trim(str); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", str); + fossil_io_cstring_free(str); +} + +FOSSIL_TEST_CASE(c_test_cstring_split) { + const char *str = "Hello,World,Test"; + size_t count; + cstring *result = fossil_io_cstring_split(str, ',', &count); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_SIZE(3, count); + ASSUME_ITS_EQUAL_CSTR("Hello", result[0]); + ASSUME_ITS_EQUAL_CSTR("World", result[1]); + ASSUME_ITS_EQUAL_CSTR("Test", result[2]); + for (size_t i = 0; i < count; i++) { + fossil_io_cstring_free(result[i]); + } + free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_replace) { + const char *str = "Hello, World!"; + const char *old = "World"; + const char *new_str = "Fossil"; + cstring result = fossil_io_cstring_replace(str, old, new_str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, Fossil!", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_to_upper) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_to_upper(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("HELLO, WORLD!", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_to_lower) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_to_lower(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("hello, world!", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_starts_with) { + const char *str = "Hello, World!"; + const char *prefix = "Hello"; + ASSUME_ITS_TRUE(fossil_io_cstring_starts_with(str, prefix)); +} + +FOSSIL_TEST_CASE(c_test_cstring_ends_with) { + const char *str = "Hello, World!"; + const char *suffix = "World!"; + ASSUME_ITS_TRUE(fossil_io_cstring_ends_with(str, suffix)); +} + +FOSSIL_TEST_CASE(c_test_cstring_substring) { + const char *str = "Hello, World!"; + cstring result = fossil_io_cstring_substring(str, 7, 5); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("World", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_reverse) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_reverse(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("!dlroW ,olleH", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_contains) { + const char *str = "Hello, World!"; + const char *substr = "World"; + ASSUME_ITS_TRUE(fossil_io_cstring_contains(str, substr)); +} + +FOSSIL_TEST_CASE(c_test_cstring_repeat) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_repeat(str, 3); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("HelloHelloHello", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_strip) { + const char *str = "!!!Hello, World!!!"; + cstring result = fossil_io_cstring_strip(str, '!'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_count) { + const char *str = "Hello, World! Hello, Fossil!"; + const char *substr = "Hello"; + size_t count = fossil_io_cstring_count(str, substr); + ASSUME_ITS_EQUAL_SIZE(2, count); +} + +FOSSIL_TEST_CASE(c_test_cstring_pad_left) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_pad_left(str, 10, '*'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("*****Hello", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_pad_right) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_pad_right(str, 10, '*'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello*****", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(c_test_cstring_stream_create_and_free) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + ASSUME_NOT_CNULL(stream); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(c_test_cstring_stream_write_and_read) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + fossil_io_cstring_stream_write(stream, "Hello, World!"); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(c_test_cstring_stream_multiple_writes) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + fossil_io_cstring_stream_write(stream, "Hello, "); + fossil_io_cstring_stream_write(stream, "World!"); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(c_test_cstring_stream_empty_read) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("", result); + fossil_io_cstring_stream_free(stream); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_string_tests) { + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_create_and_free); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_copy); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_concat); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_length); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_compare); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_trim); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_split); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_replace); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_to_upper); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_to_lower); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_starts_with); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_ends_with); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_substring); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_reverse); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_contains); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_repeat); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_strip); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_count); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_pad_left); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_pad_right); + + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_stream_create_and_free); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_stream_write_and_read); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_stream_multiple_writes); + FOSSIL_TEST_ADD(c_string_suite, c_test_cstring_stream_empty_read); + + FOSSIL_TEST_REGISTER(c_string_suite); +} diff --git a/code/tests/cases/test_cstring.cpp b/code/tests/cases/test_cstring.cpp new file mode 100644 index 0000000..6e9c456 --- /dev/null +++ b/code/tests/cases/test_cstring.cpp @@ -0,0 +1,466 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include + +#include "fossil/io/framework.h" + + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Utilites +// * * * * * * * * * * * * * * * * * * * * * * * * +// Setup steps for things like test fixtures and +// mock objects are set here. +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Define the test suite and add test cases +FOSSIL_TEST_SUITE(cpp_string_suite); +fossil_fstream_t cpp_string; + +// Setup function for the test suite +FOSSIL_SETUP(cpp_string_suite) { + // Setup code here +} + +// Teardown function for the test suite +FOSSIL_TEARDOWN(cpp_string_suite) { + // Teardown code here +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Cases +// * * * * * * * * * * * * * * * * * * * * * * * * +// The test cases below are provided as samples, inspired +// by the Meson build system's approach of using test cases +// as samples for library usage. +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_CASE(cpp_test_cstring_create_and_free) { + const char *init = "Hello, World!"; + cstring str = fossil_io_cstring_create(init); + ASSUME_NOT_CNULL(str); + ASSUME_ITS_EQUAL_CSTR(init, str); + fossil_io_cstring_free(str); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_copy) { + const char *init = "Hello, World!"; + cstring str = fossil_io_cstring_create(init); + cstring copy = fossil_io_cstring_copy(str); + ASSUME_NOT_CNULL(copy); + ASSUME_ITS_EQUAL_CSTR(init, copy); + fossil_io_cstring_free(str); + fossil_io_cstring_free(copy); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_concat) { + const char *s1 = "Hello, "; + const char *s2 = "World!"; + cstring result = fossil_io_cstring_concat(s1, s2); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_length) { + const char *str = "Hello, World!"; + size_t length = fossil_io_cstring_length(str); + ASSUME_ITS_EQUAL_SIZE(strlen(str), length); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_compare) { + const char *s1 = "Hello"; + const char *s2 = "Hello"; + const char *s3 = "World"; + ASSUME_ITS_EQUAL_I32(0, fossil_io_cstring_compare(s1, s2)); + ASSUME_ITS_TRUE(fossil_io_cstring_compare(s1, s3) < 0); + ASSUME_ITS_TRUE(fossil_io_cstring_compare(s3, s1) > 0); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_trim) { + cstring str = fossil_io_cstring_create(" Hello, World! "); + fossil_io_cstring_trim(str); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", str); + fossil_io_cstring_free(str); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_split) { + const char *str = "Hello,World,Test"; + size_t count; + cstring *result = fossil_io_cstring_split(str, ',', &count); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_SIZE(3, count); + ASSUME_ITS_EQUAL_CSTR("Hello", result[0]); + ASSUME_ITS_EQUAL_CSTR("World", result[1]); + ASSUME_ITS_EQUAL_CSTR("Test", result[2]); + for (size_t i = 0; i < count; i++) { + fossil_io_cstring_free(result[i]); + } + free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_replace) { + const char *str = "Hello, World!"; + const char *old = "World"; + const char *new_str = "Fossil"; + cstring result = fossil_io_cstring_replace(str, old, new_str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, Fossil!", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_to_upper) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_to_upper(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("HELLO, WORLD!", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_to_lower) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_to_lower(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("hello, world!", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_starts_with) { + const char *str = "Hello, World!"; + const char *prefix = "Hello"; + ASSUME_ITS_TRUE(fossil_io_cstring_starts_with(str, prefix)); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_ends_with) { + const char *str = "Hello, World!"; + const char *suffix = "World!"; + ASSUME_ITS_TRUE(fossil_io_cstring_ends_with(str, suffix)); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_substring) { + const char *str = "Hello, World!"; + cstring result = fossil_io_cstring_substring(str, 7, 5); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("World", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_reverse) { + cstring str = fossil_io_cstring_create("Hello, World!"); + cstring result = fossil_io_cstring_reverse(str); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("!dlroW ,olleH", result); + fossil_io_cstring_free(str); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_contains) { + const char *str = "Hello, World!"; + const char *substr = "World"; + ASSUME_ITS_TRUE(fossil_io_cstring_contains(str, substr)); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_repeat) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_repeat(str, 3); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("HelloHelloHello", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_strip) { + const char *str = "!!!Hello, World!!!"; + cstring result = fossil_io_cstring_strip(str, '!'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_count) { + const char *str = "Hello, World! Hello, Fossil!"; + const char *substr = "Hello"; + size_t count = fossil_io_cstring_count(str, substr); + ASSUME_ITS_EQUAL_SIZE(2, count); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_pad_left) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_pad_left(str, 10, '*'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("*****Hello", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_pad_right) { + const char *str = "Hello"; + cstring result = fossil_io_cstring_pad_right(str, 10, '*'); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello*****", result); + fossil_io_cstring_free(result); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_create_and_free) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + ASSUME_NOT_CNULL(stream); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_write_and_read) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + fossil_io_cstring_stream_write(stream, "Hello, World!"); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_multiple_writes) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + fossil_io_cstring_stream_write(stream, "Hello, "); + fossil_io_cstring_stream_write(stream, "World!"); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_empty_read) { + fossil_io_cstring_stream *stream = fossil_io_cstring_stream_create(1024); + ccstring result = fossil_io_cstring_stream_read(stream); + ASSUME_NOT_CNULL(result); + ASSUME_ITS_EQUAL_CSTR("", result); + fossil_io_cstring_stream_free(stream); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_create_and_free) { + fossil::io::CString str("Hello, World!"); + ASSUME_NOT_CNULL(str.str()); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", str.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_copy) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString copy = fossil::io::CString::copy("Hello, World!"); + ASSUME_NOT_CNULL(copy.str()); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", copy.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_concat) { + fossil::io::CString result = fossil::io::CString::concat("Hello, ", "World!"); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_length) { + fossil::io::CString str("Hello, World!"); + size_t length = str.length(); + ASSUME_ITS_EQUAL_SIZE(strlen("Hello, World!"), length); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_compare) { + fossil::io::CString s1("Hello"); + fossil::io::CString s2("Hello"); + fossil::io::CString s3("World"); + ASSUME_ITS_EQUAL_I32(0, s1.compare("Hello")); + ASSUME_ITS_TRUE(s1.compare("World") < 0); + ASSUME_ITS_TRUE(s3.compare("Hello") > 0); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_trim) { + fossil::io::CString str(" Hello, World! "); + str.trim(); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", str.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_split) { + fossil::io::CString str("Hello,World,Test"); + size_t count; + std::vector result = str.split(',', &count); + ASSUME_ITS_EQUAL_SIZE(3, count); + ASSUME_ITS_EQUAL_CSTR("Hello", result[0].c_str()); + ASSUME_ITS_EQUAL_CSTR("World", result[1].c_str()); + ASSUME_ITS_EQUAL_CSTR("Test", result[2].c_str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_replace) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString result = str.replace("World", "Fossil"); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("Hello, Fossil!", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_to_upper) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString result = str.to_upper(); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("HELLO, WORLD!", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_to_lower) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString result = str.to_lower(); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("hello, world!", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_starts_with) { + fossil::io::CString str("Hello, World!"); + ASSUME_ITS_TRUE(str.starts_with("Hello")); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_ends_with) { + fossil::io::CString str("Hello, World!"); + ASSUME_ITS_TRUE(str.ends_with("World!")); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_substring) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString result = str.substring(7, 5); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("World", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_reverse) { + fossil::io::CString str("Hello, World!"); + fossil::io::CString result = str.reverse(); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("!dlroW ,olleH", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_contains) { + fossil::io::CString str("Hello, World!"); + ASSUME_ITS_TRUE(str.contains("World")); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_repeat) { + fossil::io::CString str("Hello"); + fossil::io::CString result = str.repeat(3); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("HelloHelloHello", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_strip) { + fossil::io::CString str("!!!Hello, World!!!"); + fossil::io::CString result = str.strip('!'); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("Hello, World", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_count) { + fossil::io::CString str("Hello, World! Hello, Fossil!"); + size_t count = str.count("Hello"); + ASSUME_ITS_EQUAL_SIZE(2, count); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_pad_left) { + fossil::io::CString str("Hello"); + fossil::io::CString result = str.pad_left(10, '*'); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("*****Hello", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_class_pad_right) { + fossil::io::CString str("Hello"); + fossil::io::CString result = str.pad_right(10, '*'); + ASSUME_NOT_CNULL(result.str()); + ASSUME_ITS_EQUAL_CSTR("Hello*****", result.str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_class_create_and_free) { + fossil::io::CStringStream stream(1024); + ASSUME_NOT_CNULL(stream.read().c_str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_class_write_and_read) { + fossil::io::CStringStream stream(1024); + stream.write("Hello, World!"); + std::string result = stream.read(); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result.c_str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_class_multiple_writes) { + fossil::io::CStringStream stream(1024); + stream.write("Hello, "); + stream.write("World!"); + std::string result = stream.read(); + ASSUME_ITS_EQUAL_CSTR("Hello, World!", result.c_str()); +} + +FOSSIL_TEST_CASE(cpp_test_cstring_stream_class_empty_read) { + fossil::io::CStringStream stream(1024); + std::string result = stream.read(); + ASSUME_ITS_EQUAL_CSTR("", result.c_str()); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(cpp_string_tests) { + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_create_and_free); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_copy); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_concat); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_length); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_compare); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_trim); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_split); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_replace); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_to_upper); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_to_lower); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_starts_with); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_ends_with); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_substring); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_reverse); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_contains); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_repeat); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_strip); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_count); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_pad_left); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_pad_right); + + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_create_and_free); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_write_and_read); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_multiple_writes); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_empty_read); + + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_create_and_free); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_copy); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_concat); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_length); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_compare); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_trim); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_split); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_replace); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_to_upper); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_to_lower); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_starts_with); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_ends_with); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_substring); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_reverse); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_contains); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_repeat); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_strip); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_count); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_pad_left); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_class_pad_right); + + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_class_create_and_free); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_class_write_and_read); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_class_multiple_writes); + FOSSIL_TEST_ADD(cpp_string_suite, cpp_test_cstring_stream_class_empty_read); + + FOSSIL_TEST_REGISTER(cpp_string_suite); +} diff --git a/code/tests/meson.build b/code/tests/meson.build index 9769f47..00c9977 100644 --- a/code/tests/meson.build +++ b/code/tests/meson.build @@ -2,7 +2,7 @@ if get_option('with_test').enabled() run_command(['python3', 'tools' / 'generate-runner.py'], check: true) test_c = ['unit_runner.c'] - test_cases = ['parser', 'stream', 'soap', 'input', 'error', 'keyboard', 'network', 'serialize'] + test_cases = ['parser', 'stream', 'soap', 'input', 'error', 'keyboard', 'network', 'serialize', 'cstring'] foreach cases : test_cases test_c += ['cases' / 'test_' + cases + '.c']