Initial commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.chinook/
|
||||||
|
.environ/
|
||||||
|
.vscode/
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
name: strview
|
||||||
|
gpid: malunal
|
||||||
|
semv: 1.0.0
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- remote: git@git.erasit.com:malunal/microtest
|
||||||
|
branch: v1.0.0
|
||||||
|
- remote: git@git.erasit.com:malunal/types
|
||||||
|
branch: v1.0.0
|
||||||
|
|
||||||
|
targets:
|
||||||
|
- name: malunal.strview
|
||||||
|
type: archive
|
||||||
|
deps:
|
||||||
|
- malunal.types
|
||||||
|
srcs:
|
||||||
|
- ./sources/strview.c
|
||||||
|
|
||||||
|
tests:
|
||||||
|
- name: malunal.strview.tests
|
||||||
|
type: program
|
||||||
|
deps:
|
||||||
|
- malunal.microtest
|
||||||
|
- malunal.strview
|
||||||
|
srcs:
|
||||||
|
- ./tests/strview.c
|
||||||
|
|
||||||
|
exports:
|
||||||
|
- malunal.strview
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* @file strview.h
|
||||||
|
* @brief Contains the definition of the string view structure and functions.
|
||||||
|
* @author John Christman (sorakatadzuma@gmail.com)
|
||||||
|
* @copyright Malunal Studios, LLC.
|
||||||
|
*/
|
||||||
|
#include "malunal/type.h"
|
||||||
|
|
||||||
|
#ifndef MALUNAL_STRVIEW_HEADER
|
||||||
|
#define MALUNAL_STRVIEW_HEADER
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def STRVIEW_NPOS
|
||||||
|
* @brief Defines the null position of a string view.
|
||||||
|
* @details When received as a return result: indicates that the function could
|
||||||
|
* not operate on the strview provided, or indicates that the function
|
||||||
|
* would or did iterate beyond the bounds of the string view.
|
||||||
|
*/
|
||||||
|
#define STRVIEW_NPOS ((malunal_size_t)-1)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct strview
|
||||||
|
* @brief Defines a string view.
|
||||||
|
* @details A string view is a length based addressable pointer to an array of
|
||||||
|
* characters. Often, it is used in place of regular strings to remove
|
||||||
|
* the reliance on null-terminated strings and needing to store a copy
|
||||||
|
* of the null-terminated string, or its substring.
|
||||||
|
*/
|
||||||
|
define_struct(strview) {
|
||||||
|
/**
|
||||||
|
* @brief A pointer to the beginning of the string view.
|
||||||
|
* @details This points to the beginning of the string view, treating it like
|
||||||
|
* an array of characters that can be indexed.
|
||||||
|
*/
|
||||||
|
malunal_cstr_t beg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A pointer to the ending of the string view.
|
||||||
|
* @details This points to the ending of the string view, treating it like an
|
||||||
|
* array of characters that can be indexed.
|
||||||
|
*/
|
||||||
|
malunal_cstr_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a string view from the provided @c data and @c length.
|
||||||
|
* @param data A pointer to the data of the string view.
|
||||||
|
* @param length The length of the string view in characters.
|
||||||
|
* @returns The constructed string view.
|
||||||
|
*/
|
||||||
|
strview_t
|
||||||
|
strview(
|
||||||
|
malunal_cstr_t data,
|
||||||
|
malunal_size_t length
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a string view from the provided null-terminated @c data.
|
||||||
|
* @param data A pointer to the data of the string view.
|
||||||
|
* @returns The constructed string view.
|
||||||
|
*/
|
||||||
|
strview_t
|
||||||
|
strview_from_cstr(
|
||||||
|
malunal_cstr_t data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the length of the string view.
|
||||||
|
* @param self A pointer to the string view to get the length of.
|
||||||
|
* @returns The length of the string view, zero if the pointer is null.
|
||||||
|
*/
|
||||||
|
malunal_size_t
|
||||||
|
strview_length(
|
||||||
|
strview_iptr_t self
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Moves the start of the view forward by @c count.
|
||||||
|
* @param self The strview to trim by @c count.
|
||||||
|
* @param count The number of characters to trim by.
|
||||||
|
* @remarks This will mutate the provided string view directly. Provide a copy
|
||||||
|
* of the string view you wish to trim, if you want to preserve the
|
||||||
|
* original.
|
||||||
|
*/
|
||||||
|
malunal_void_t
|
||||||
|
strview_ltrim(
|
||||||
|
strview_mptr_t self,
|
||||||
|
malunal_size_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Moves the end of the view backward by @c count.
|
||||||
|
* @param self The strview to trim by @c count.
|
||||||
|
* @param count The number of characters to trim by.
|
||||||
|
* @remarks This will mutate the provided string view directly. Provide a copy
|
||||||
|
* of the string view you wish to trim, if you want to preserve the
|
||||||
|
* original.
|
||||||
|
*/
|
||||||
|
malunal_void_t
|
||||||
|
strview_rtrim(
|
||||||
|
strview_mptr_t self,
|
||||||
|
malunal_size_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a subview of the current string view.
|
||||||
|
* @param self The string view to subview.
|
||||||
|
* @param start Where to subview from.
|
||||||
|
* @param count How many characters to subview.
|
||||||
|
* @returns The constructed subview.
|
||||||
|
* @remarks The result of this function can be a string view with null data and
|
||||||
|
* zero length if the input string view could not be subviewed.
|
||||||
|
*/
|
||||||
|
strview_t
|
||||||
|
strview_subview(
|
||||||
|
strview_iptr_t self,
|
||||||
|
malunal_size_t start,
|
||||||
|
malunal_size_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the equality result of two string views.
|
||||||
|
* @param self The string view to compare against.
|
||||||
|
* @param other The string view to compare with.
|
||||||
|
* @retval true If the comparison of the two string views is zero.
|
||||||
|
* @retval false If the comparision of the two string views is non-zero.
|
||||||
|
*/
|
||||||
|
malunal_bool_t
|
||||||
|
strview_equals(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the comparison result of two string views.
|
||||||
|
* @param self The string view to compare against.
|
||||||
|
* @param other The string view to compare with.
|
||||||
|
* @retval -1 If @c self is comparatively less than @c other.
|
||||||
|
* @retval 0 If @c self is comparatively equal to @c other.
|
||||||
|
* @retval 1 if @c self is comparatively more than @c other.
|
||||||
|
*/
|
||||||
|
malunal_int32_t
|
||||||
|
strview_compare(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicates if @c self starts with @c other.
|
||||||
|
* @param self The string view to compare against.
|
||||||
|
* @param other The string view to compare with.
|
||||||
|
* @retval true If @c self does start with @c other.
|
||||||
|
* @retval false If @c self does not start with @c other.
|
||||||
|
*/
|
||||||
|
malunal_bool_t
|
||||||
|
strview_starts_with(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicates if @c self ends with @c other.
|
||||||
|
* @param self The string view to compare against.
|
||||||
|
* @param other The string view to compare with.
|
||||||
|
* @retval true If @c self does end with @c other.
|
||||||
|
* @retval false If @c self does not end with @c other.
|
||||||
|
*/
|
||||||
|
malunal_bool_t
|
||||||
|
strview_ends_with(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicates if @c self contains @c other.
|
||||||
|
* @param self The string view to compare against.
|
||||||
|
* @param other The string view to compare with.
|
||||||
|
* @retval true If @c self does contain @c other.
|
||||||
|
* @retval false If @c self does not contain @c other.
|
||||||
|
*/
|
||||||
|
malunal_bool_t
|
||||||
|
strview_contains(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* MALUNAL_STRVIEW_HEADER */
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "malunal/strview.h"
|
||||||
|
|
||||||
|
|
||||||
|
strview_t
|
||||||
|
strview(
|
||||||
|
malunal_cstr_t data,
|
||||||
|
malunal_size_t length
|
||||||
|
) {
|
||||||
|
return (strview_t) {
|
||||||
|
.beg = data,
|
||||||
|
.end = data + length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
strview_t
|
||||||
|
strview_from_cstr(
|
||||||
|
malunal_cstr_t data
|
||||||
|
) {
|
||||||
|
return data != null
|
||||||
|
? strview(data, strlen(data))
|
||||||
|
: strview(null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_size_t
|
||||||
|
strview_length(
|
||||||
|
strview_iptr_t self
|
||||||
|
) {
|
||||||
|
return self != null
|
||||||
|
? self->end - self->beg
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_void_t
|
||||||
|
strview_ltrim(
|
||||||
|
strview_mptr_t self,
|
||||||
|
malunal_size_t count
|
||||||
|
) {
|
||||||
|
malunal_size_t length =
|
||||||
|
strview_length(self);
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (length < count)
|
||||||
|
count = length;
|
||||||
|
self->beg += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_void_t
|
||||||
|
strview_rtrim(
|
||||||
|
strview_mptr_t self,
|
||||||
|
malunal_size_t count
|
||||||
|
) {
|
||||||
|
malunal_size_t length =
|
||||||
|
strview_length(self);
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (length < count)
|
||||||
|
count = length;
|
||||||
|
self->end -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
strview_t
|
||||||
|
strview_subview(
|
||||||
|
strview_iptr_t self,
|
||||||
|
malunal_size_t start,
|
||||||
|
malunal_size_t count
|
||||||
|
) {
|
||||||
|
if (self == null)
|
||||||
|
return strview(null, 0);
|
||||||
|
|
||||||
|
strview_t res = { self->beg, self->end };
|
||||||
|
malunal_size_t len = strview_length(&res);
|
||||||
|
if (start > len)
|
||||||
|
return strview(null, 0);
|
||||||
|
|
||||||
|
strview_ltrim(&res, start);
|
||||||
|
len = strview_length(&res);
|
||||||
|
if (count > len)
|
||||||
|
return strview(null, 0);
|
||||||
|
|
||||||
|
strview_rtrim(&res, len - count);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_bool_t
|
||||||
|
strview_equals(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
) {
|
||||||
|
return strview_compare(self, other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_int32_t
|
||||||
|
strview_compare(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
) {
|
||||||
|
if (self == null || other == null) {
|
||||||
|
if (self < other) return -1;
|
||||||
|
if (self > other) return 1;
|
||||||
|
if (self == other) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_size_t hlen = strview_length(self);
|
||||||
|
malunal_size_t nlen = strview_length(other);
|
||||||
|
if (hlen < nlen) return -1;
|
||||||
|
if (hlen > nlen) return 1;
|
||||||
|
|
||||||
|
malunal_size_t smallest = hlen < nlen ? hlen : nlen;
|
||||||
|
return strncmp(self->beg, other->beg, smallest);
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_bool_t
|
||||||
|
strview_starts_with(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
) {
|
||||||
|
if (self == null) return false;
|
||||||
|
if (other == null) return true;
|
||||||
|
|
||||||
|
malunal_size_t hlen = strview_length(self);
|
||||||
|
malunal_size_t nlen = strview_length(other);
|
||||||
|
if (nlen == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return hlen >= nlen
|
||||||
|
? strncmp(self->beg, other->beg, nlen) == 0
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_bool_t
|
||||||
|
strview_ends_with(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
) {
|
||||||
|
if (self == null) return false;
|
||||||
|
if (other == null) return true;
|
||||||
|
|
||||||
|
malunal_size_t hlen = strview_length(self);
|
||||||
|
malunal_size_t nlen = strview_length(other);
|
||||||
|
if (nlen == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hlen < nlen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
malunal_size_t diff = hlen - nlen;
|
||||||
|
malunal_cstr_t beg = self->beg + diff;
|
||||||
|
return strncmp(beg, other->beg, nlen) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
malunal_bool_t
|
||||||
|
strview_contains(
|
||||||
|
strview_iptr_t self,
|
||||||
|
strview_iptr_t other
|
||||||
|
) {
|
||||||
|
if (self == null) return false;
|
||||||
|
if (other == null) return true;
|
||||||
|
|
||||||
|
malunal_size_t hlen = strview_length(self);
|
||||||
|
malunal_size_t nlen = strview_length(other);
|
||||||
|
if (nlen == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hlen < nlen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Poor man's sliding window
|
||||||
|
malunal_cstr_t beg = self->beg;
|
||||||
|
while (hlen >= nlen) {
|
||||||
|
if (strncmp(beg, other->beg, nlen) == 0)
|
||||||
|
return true;
|
||||||
|
beg++;
|
||||||
|
hlen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
+378
@@ -0,0 +1,378 @@
|
|||||||
|
#include "malunal/microtest.h"
|
||||||
|
#include "malunal/strview.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* Construction: strview() / strview_from_cstr()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_construct, from_data_and_length) {
|
||||||
|
malunal_cstr_t data = "hello world";
|
||||||
|
strview_t view = strview(data, 5);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(view.beg, data);
|
||||||
|
MICROTEST_EXPECT_EQ(view.end, data + 5);
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)5);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_construct, zero_length) {
|
||||||
|
malunal_cstr_t data = "hello";
|
||||||
|
strview_t view = strview(data, 0);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)0);
|
||||||
|
MICROTEST_EXPECT_EQ(view.beg, view.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_construct, from_cstr_matches_strlen) {
|
||||||
|
malunal_cstr_t data = "hello world";
|
||||||
|
strview_t view = strview_from_cstr(data);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)strlen(data));
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(view.beg, data, strview_length(&view)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_construct, from_cstr_empty) {
|
||||||
|
strview_t view = strview_from_cstr("");
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_construct, from_cstr_matches_manual_construction) {
|
||||||
|
malunal_cstr_t data = "matching";
|
||||||
|
strview_t fromcstr = strview_from_cstr(data);
|
||||||
|
strview_t manual = strview(data, (malunal_size_t)strlen(data));
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&fromcstr, &manual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_length()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_length, reports_correct_length) {
|
||||||
|
strview_t view = strview_from_cstr("0123456789");
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)10);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_length, null_self_returns_zero) {
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(null), (malunal_size_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_ltrim()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_ltrim, moves_start_forward) {
|
||||||
|
strview_t view = strview_from_cstr("hello world");
|
||||||
|
strview_ltrim(&view, 6);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)5);
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(view.beg, "world", 5) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ltrim, zero_count_is_noop) {
|
||||||
|
strview_t view = strview_from_cstr("unchanged");
|
||||||
|
strview_t original = view;
|
||||||
|
|
||||||
|
strview_ltrim(&view, 0);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&view, &original));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ltrim, full_length_yields_empty_view) {
|
||||||
|
strview_t view = strview_from_cstr("hello");
|
||||||
|
strview_ltrim(&view, strview_length(&view));
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_rtrim()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_rtrim, moves_end_backward) {
|
||||||
|
strview_t view = strview_from_cstr("hello world");
|
||||||
|
strview_rtrim(&view, 6);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)5);
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(view.beg, "hello", 5) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_rtrim, zero_count_is_noop) {
|
||||||
|
strview_t view = strview_from_cstr("unchanged");
|
||||||
|
strview_t original = view;
|
||||||
|
|
||||||
|
strview_rtrim(&view, 0);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&view, &original));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_rtrim, full_length_yields_empty_view) {
|
||||||
|
strview_t view = strview_from_cstr("hello");
|
||||||
|
strview_rtrim(&view, strview_length(&view));
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_rtrim, combined_with_ltrim_isolates_middle) {
|
||||||
|
strview_t view = strview_from_cstr(" trimmed ");
|
||||||
|
strview_ltrim(&view, 2);
|
||||||
|
strview_rtrim(&view, 2);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&view), (malunal_size_t)7);
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(view.beg, "trimmed", 7) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_subview()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, middle_slice) {
|
||||||
|
strview_t view = strview_from_cstr("hello world");
|
||||||
|
strview_t sub = strview_subview(&view, 6, 5);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&sub), (malunal_size_t)5);
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(sub.beg, "world", 5) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, from_start) {
|
||||||
|
strview_t view = strview_from_cstr("hello world");
|
||||||
|
strview_t sub = strview_subview(&view, 0, 5);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(memcmp(sub.beg, "hello", 5) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, zero_count_is_empty) {
|
||||||
|
strview_t view = strview_from_cstr("hello world");
|
||||||
|
strview_t sub = strview_subview(&view, 3, 0);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&sub), (malunal_size_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, out_of_bounds_start_fails) {
|
||||||
|
/* Per the header remarks, an invalid subview yields null data and zero
|
||||||
|
* length rather than reading past the end of the source view. */
|
||||||
|
strview_t view = strview_from_cstr("hello");
|
||||||
|
strview_t sub = strview_subview(&view, 100, 1);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&sub), (malunal_size_t)0);
|
||||||
|
MICROTEST_EXPECT_NULL(sub.beg);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, count_exceeding_bounds_fails) {
|
||||||
|
strview_t view = strview_from_cstr("hello");
|
||||||
|
strview_t sub = strview_subview(&view, 3, 10);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&sub), (malunal_size_t)0);
|
||||||
|
MICROTEST_EXPECT_NULL(sub.beg);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_subview, null_self_fails) {
|
||||||
|
strview_t sub = strview_subview(null, 0, 1);
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_length(&sub), (malunal_size_t)0);
|
||||||
|
MICROTEST_EXPECT_NULL(sub.beg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_equals()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_equals, identical_content_is_equal) {
|
||||||
|
strview_t a = strview_from_cstr("identical");
|
||||||
|
strview_t b = strview_from_cstr("identical");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&a, &b));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_equals, different_content_is_not_equal) {
|
||||||
|
strview_t a = strview_from_cstr("hello");
|
||||||
|
strview_t b = strview_from_cstr("world");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_equals(&a, &b));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_equals, different_lengths_are_not_equal) {
|
||||||
|
strview_t a = strview_from_cstr("hello");
|
||||||
|
strview_t b = strview_from_cstr("hello!");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_equals(&a, &b));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_equals, empty_views_are_equal) {
|
||||||
|
strview_t a = strview_from_cstr("");
|
||||||
|
strview_t b = strview_from_cstr("");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&a, &b));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_equals, is_reflexive) {
|
||||||
|
strview_t a = strview_from_cstr("self");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_equals(&a, &a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_compare()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_compare, equal_views_compare_zero) {
|
||||||
|
strview_t a = strview_from_cstr("apple");
|
||||||
|
strview_t b = strview_from_cstr("apple");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_EQ(strview_compare(&a, &b), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_compare, lesser_view_compares_negative) {
|
||||||
|
strview_t a = strview_from_cstr("apple");
|
||||||
|
strview_t b = strview_from_cstr("banana");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_LT(strview_compare(&a, &b), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_compare, greater_view_compares_positive) {
|
||||||
|
strview_t a = strview_from_cstr("banana");
|
||||||
|
strview_t b = strview_from_cstr("apple");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_GT(strview_compare(&a, &b), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_compare, shorter_prefix_compares_negative) {
|
||||||
|
strview_t a = strview_from_cstr("app");
|
||||||
|
strview_t b = strview_from_cstr("apple");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_LT(strview_compare(&a, &b), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_starts_with()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_starts_with, true_when_prefix_matches) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_starts_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_starts_with, false_when_prefix_differs) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("world");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_starts_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_starts_with, false_when_other_longer_than_self) {
|
||||||
|
strview_t self = strview_from_cstr("hi");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_starts_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_starts_with, true_for_empty_other) {
|
||||||
|
strview_t self = strview_from_cstr("hello");
|
||||||
|
strview_t other = strview_from_cstr("");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_starts_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_starts_with, true_when_equal) {
|
||||||
|
strview_t self = strview_from_cstr("hello");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_starts_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_ends_with()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_ends_with, true_when_suffix_matches) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("world");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_ends_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ends_with, false_when_suffix_differs) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_ends_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ends_with, false_when_other_longer_than_self) {
|
||||||
|
strview_t self = strview_from_cstr("hi");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_ends_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ends_with, true_for_empty_other) {
|
||||||
|
strview_t self = strview_from_cstr("hello");
|
||||||
|
strview_t other = strview_from_cstr("");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_ends_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_ends_with, true_when_equal) {
|
||||||
|
strview_t self = strview_from_cstr("hello");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_ends_with(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* strview_contains()
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, true_when_substring_present) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("lo wo");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, false_when_substring_absent) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("xyz");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, true_for_prefix) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, true_for_suffix) {
|
||||||
|
strview_t self = strview_from_cstr("hello world");
|
||||||
|
strview_t other = strview_from_cstr("world");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, true_for_empty_other) {
|
||||||
|
strview_t self = strview_from_cstr("hello");
|
||||||
|
strview_t other = strview_from_cstr("");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_TRUE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST(strview_contains, false_when_other_longer_than_self) {
|
||||||
|
strview_t self = strview_from_cstr("hi");
|
||||||
|
strview_t other = strview_from_cstr("hello");
|
||||||
|
|
||||||
|
MICROTEST_EXPECT_FALSE(strview_contains(&self, &other));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* STRVIEW_NPOS
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
MICROTEST(strview_npos, is_max_size_value) {
|
||||||
|
MICROTEST_EXPECT_EQ(STRVIEW_NPOS, (malunal_size_t)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MICROTEST_MAIN()
|
||||||
|
|
||||||
Reference in New Issue
Block a user