Permalink
Browse files

new-assert: added stream tag.

Streams are special constructs that let users compare abitrary data
streams, by letting them provide their own read procedures. As streams
are evaluated on-the-fly, they are suitable for use when comparing very
large datasets that would not be sensible to load in memory, though they
are slightly less convenient than using `mem`.

These are designed to replace the now deprecated file assertion API.
  • Loading branch information...
Snaipe committed May 2, 2018
1 parent 39e9130 commit e2de3000266947055179a9623dac83b543117337
@@ -60,6 +60,19 @@ bool zero(const T &t) { return t.empty(); }
template <> inline bool zero<>(const char *t) { return !*t; }
template <> inline bool zero<>(const wchar_t *t) { return !*t; }
/* relops without const */
template <typename T, typename U>
inline bool operator!= (T& t, U& u) { return !(t == u); }
template <typename T, typename U>
inline bool operator<= (T& t, U& u) { return t < u || t == u; }
template <typename T, typename U>
inline bool operator> (T& t, U& u) { return !(t <= u); }
template <typename T, typename U>
inline bool operator>= (T& t, U& u) { return !(t < u); }
/* *INDENT-OFF* */
}}}
/* *INDENT-ON* */
@@ -0,0 +1,56 @@
/*
* The MIT License (MIT)
*
* Copyright © 2018 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_INTERNAL_STREAM_H_
#define CRITERION_INTERNAL_STREAM_H_
#define CRI_ASSERT_TEST_TAG_stream ,
#define CRI_ASSERT_TEST_TAGC_stream() ,
#define CRI_ASSERT_TYPE_TAG_stream struct cr_stream,
#define CRI_ASSERT_TYPE_TAG_ID_stream stream,
#ifdef __cplusplus
# include <string>
# include <ostream>
inline bool operator==(criterion::stream &s1, criterion::stream &s2)
{
return cr_user_stream_eq(&s1, &s2);
}
inline bool operator<(criterion::stream &s1, criterion::stream &s2)
{
return cr_user_stream_lt(&s1, &s2);
}
inline std::ostream &operator<<(std::ostream &os, const criterion::stream &s)
{
char *str = cr_user_stream_tostr(&s);
os << std::string(str);
free(str);
return os;
}
#endif /* !__cplusplus */
#endif /* !CRITERION_INTERNAL_STREAM_H_ */
@@ -208,7 +208,6 @@ std::wstring cri_val_escape(const wchar_t (&s)[N])
} ())
# define CRI_ASSERT_UNPRINTABLE(Var) CRI_USER_TOSTR(, Var)
# define CRI_ASSERT_NAMESPACES \
using namespace std::rel_ops; \
using namespace criterion::internal::operators
# define CRI_USER_TOSTR_ARR(Str, Arr, Tag) \
@@ -433,6 +433,7 @@
#endif /* !CRITERION_DOCGEN */
#include "memory.h"
#include "stream.h"

This comment has been minimized.

@stdevMauricio

stdevMauricio May 14, 2018

Contributor

I've been unable to run my tests since you added this line. Is it OK?

This comment has been minimized.

@Snaipe

Snaipe May 14, 2018

Owner

What errors are you getting? Perhaps open an issue with as much detail as possible, if it's a stl issue, it needs to be investigated

/* Internals */
@@ -24,6 +24,8 @@
#ifndef CRITERION_NEW_MEMORY_H_
#define CRITERION_NEW_MEMORY_H_
#include "../internal/common.h"
struct cr_mem {
const void *data;
size_t size;
@@ -0,0 +1,109 @@
/*
* The MIT License (MIT)
*
* Copyright © 2018 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_NEW_STREAM_H_
#define CRITERION_NEW_STREAM_H_
#include <stddef.h>
#include "../internal/common.h"
#define CR_STREAM_BUFSIZE 4096
struct cri_stream_data {
int dirty;
int cmp;
size_t ref;
size_t cursor;
size_t remaining;
char buffer[CR_STREAM_BUFSIZE];
};
struct cr_stream {
void *cookie;
int (*read)(void *cookie, void *buf, size_t *size);
void (*close)(void *cookie);
#ifdef __cplusplus
template <typename T>
cr_stream(T *cookie,
int (*read)(void *cookie, void *buf, size_t *size),
void (*close)(void *cookie) = nullptr);
inline cr_stream(const cr_stream &other)
{
other.cri_data->ref++;
cookie = other.cookie;
read = other.read;
close = other.close;
cri_data = other.cri_data;
}
inline ~cr_stream();
#endif
/* Internals. Do not poke at. */
#ifdef __cplusplus
private:
#endif
struct cri_stream_data *cri_data;
};
CR_BEGIN_C_API
CR_API void cr_stream_init(struct cr_stream *s);
CR_API void cr_stream_close(struct cr_stream *s);
CR_API int cr_user_stream_eq(struct cr_stream *s1, struct cr_stream *s2);
CR_API int cr_user_stream_lt(struct cr_stream *s1, struct cr_stream *s2);
CR_API char *cr_user_stream_tostr(const struct cr_stream *s);
CR_END_C_API
#ifdef __cplusplus
namespace criterion {
using stream = cr_stream;
}
inline bool operator==(criterion::stream &s1, criterion::stream &s2);
inline bool operator<(criterion::stream &s1, criterion::stream &s2);
inline std::ostream &operator<<(std::ostream &os, const criterion::stream &s);
template <typename T>
cr_stream::cr_stream(T *cookie,
int (*read)(void *cookie, void *buf, size_t *size),
void (*close)(void *cookie))
: cookie(static_cast<void *>(cookie))
, read(read)
, close(close)
, cri_data(nullptr)
{
cr_stream_init(this);
}
inline cr_stream::~cr_stream() { cr_stream_close(this); }
#endif /* !__cplusplus */
#include "../internal/assert/stream.h"
#endif /* !CRITERION_NEW_STREAM_H_ */
@@ -115,3 +115,59 @@ Test(asserts, array) {
/* Here cr_assert(eq(mem, mem_s1, mem_s2)) would not have worked */
cr_assert(eq(type(struct dummy_struct)[2], s1, s2));
}
struct array_cursor {
size_t off;
size_t size;
void *buf;
};
static int read_array(void *cookie, void *buffer, size_t *size)
{
struct array_cursor *arr = cookie;
size_t rem = *size;
if (rem > arr->size - arr->off) {
rem = arr->size - arr->off;
}
memcpy(buffer, (char *) arr->buf + arr->off, rem);
arr->off += rem;
*size = rem;
return 0;
}
Test(asserts, stream) {
struct array_cursor arr1 = {
.size = 4 * sizeof (int),
.buf = &(int[4]) { 1, 2, 3, 4 },
};
struct array_cursor arr2 = {
.size = 4 * sizeof (int),
.buf = &(int[4]) { 4, 3, 2, 1 },
};
/* we can compare data with the general purpose stream API, by providing
a read function, and optionally a close function. */
struct cr_stream s1 = {
.cookie = &arr1,
.read = read_array,
};
struct cr_stream s2 = {
.cookie = &arr2,
.read = read_array,
};
cr_stream_init(&s1);
cr_stream_init(&s2);
/* Note that this consumes both streams. Criterion will do the right thing
if both streams are used in complex criteria by providing consistent
comparison results between s1 and s2, but you can't compare either
of them to any other stream without re-creating a fresh stream. */
cr_assert(ne(stream, s1, s2));
cr_stream_close(&s1);
cr_stream_close(&s2);
}
@@ -117,6 +117,52 @@ Test(asserts, array) {
cr_assert(eq(type(struct dummy_struct)[2], s1, s2));
}
struct array_cursor {
size_t off;
size_t size;
const void *buf;
};
static int read_array(void *cookie, void *buffer, size_t *size)
{
array_cursor *arr = static_cast<array_cursor*>(cookie);
size_t rem = *size;
if (rem > arr->size - arr->off) {
rem = arr->size - arr->off;
}
std::memcpy(buffer, (char *) arr->buf + arr->off, rem);
arr->off += rem;
*size = rem;
return 0;
}
Test(asserts, stream) {
struct array_cursor arr1 = {
0,
sizeof ("hello world"),
"hello world",
};
struct array_cursor arr2 = {
0,
sizeof ("dlrow olleh"),
"dlrow olleh",
};
/* we can compare binary data with the general purpose stream API, by
a read function, and optionally a close function. */
criterion::stream s1 = { &arr1, read_array };
criterion::stream s2 = { &arr2, read_array };
/* Note that this consumes both streams. Criterion will do the right thing
if both streams are used in complex criteria by providing consistent
comparison results between s1 and s2, but you can't compare either
of them to any other stream without re-creating a fresh stream. */
cr_assert(ne(stream, s1, s2));
}
Test(asserts, exception) {
cr_expect(throw (std::runtime_error, {}));
cr_assert(throw (std::invalid_argument, throw std::invalid_argument("some message")));
Oops, something went wrong.

0 comments on commit e2de300

Please sign in to comment.