[vte] stream: Compress data with zlib
- From: Egmont Koblinger <egmontkob src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] stream: Compress data with zlib
- Date: Sun, 14 Dec 2014 22:26:59 +0000 (UTC)
commit ab8b3a3465625e08e4aa5657d13d54b6818a231a
Author: Egmont Koblinger <egmont gmail com>
Date: Sun Dec 14 23:14:30 2014 +0100
stream: Compress data with zlib
Compression is implemented in "boa", a new layer between the "snake" storing
64kB units and the buffering layer. Each 64kB unit is compressed separately,
and we rely on the file system leaving sparse blocks.
https://bugzilla.gnome.org/show_bug.cgi?id=738121
https://bugzilla.gnome.org/show_bug.cgi?id=738601
configure.ac | 2 +-
src/vtestream-file.h | 723 ++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 580 insertions(+), 145 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4b11215..86522b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -208,7 +208,7 @@ AC_CHECK_FUNCS([ceil floor round])
# Search for the required modules.
-VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-$GTK_API_VERSION >=
$GTK_REQUIRED gobject-2.0 gio-2.0 gio-unix-2.0"
+VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-$GTK_API_VERSION >=
$GTK_REQUIRED gobject-2.0 gio-2.0 gio-unix-2.0 zlib"
PKG_CHECK_MODULES([VTE],[$VTE_PKGS])
AC_SUBST([VTE_PKGS])
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index f56cffb..bc41215 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -22,7 +22,7 @@
*/
/*
- * VteFileStream is implemented as two layers above each other.
+ * VteFileStream is implemented as three layers above each other.
*
* o The bottom layer is VteSnake. It provides a mapping from logical offsets
* to physical file offsets, storing the stream in at most 3 continuous
@@ -32,7 +32,9 @@
* random-access-read of a single block, random-access-overwrite of a single
* block within the stream, write (append) a single block right after the
* current head, advancing the tail by arbitrary number of blocks, and
- * resetting.
+ * resetting. The appended block can be shorter, in that case we still
+ * advance by 64kB and let the operating system leave a gap (sparse blocks)
+ * in the file which is crucial for compression.
*
* (Random-access-overwrite within the existing area is a rare event, occurs
* only when the terminal window size changes. We use it to redo differently
@@ -46,13 +48,23 @@
* the tail is kinda like a snake, and the mapping to file offsets reminds
* me of the well-known game on old mobile phones.
*
+ * o The middle layer is called VteBoa. It does compression and is planned to
+ * do encryption along with integrity check. It has (almost) the same API as
+ * the snake, but the blocksize is a bit smaller to leave room for the
+ * required overhead.
+ *
+ * The name was chosen because the world of encryption is full of three
+ * letter abbreviations. At this moment we're planning to use GNU TLS's
+ * method for doing AES GCM. Also, because grown-ups might think it's a hat,
+ * when actually it's a boa constrictor digesting an elephant :)
+ *
* o The top layer is VteFileStream. It does buffering and caching. As opposed
* to the previous layers, this one provides methods on arbitrary amount of
* data. It doesn't offer random-access-writes, instead, it offers appending
* data, and truncating the head (undoing the latest appends). Write
- * requests are batched up until there's a complete block to be written to
- * disk. Read requests are answered by reading possibly more underlying
- * blocks, and sped up by caching the result.
+ * requests are batched up until there's a complete block to be compressed
+ * and written to disk. Read requests are answered by reading and decrypting
+ * possibly more underlying blocks, and sped up by caching the result.
*
* Design discussions: https://bugzilla.gnome.org/show_bug.cgi?id=738601
*/
@@ -62,6 +74,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <zlib.h>
#include "vteutils.h"
@@ -70,12 +83,16 @@
typedef guint32 _vte_block_datalength_t;
#else
/* Smaller sizes for unit testing */
-# define VTE_SNAKE_BLOCKSIZE 7
+# define VTE_SNAKE_BLOCKSIZE 8
typedef guint8 _vte_block_datalength_t;
#endif
-#define ALIGN_SNAKE(x) ((x) / VTE_SNAKE_BLOCKSIZE * VTE_SNAKE_BLOCKSIZE)
-#define MOD_SNAKE(x) ((x) % VTE_SNAKE_BLOCKSIZE)
+#define VTE_BLOCK_DATALENGTH_SIZE sizeof(_vte_block_datalength_t)
+#define VTE_BOA_BLOCKSIZE (VTE_SNAKE_BLOCKSIZE - VTE_BLOCK_DATALENGTH_SIZE)
+
+#define OFFSET_BOA_TO_SNAKE(x) ((x) / VTE_BOA_BLOCKSIZE * VTE_SNAKE_BLOCKSIZE)
+#define ALIGN_BOA(x) ((x) / VTE_BOA_BLOCKSIZE * VTE_BOA_BLOCKSIZE)
+#define MOD_BOA(x) ((x) % VTE_BOA_BLOCKSIZE)
/******************************************************************************************/
@@ -137,13 +154,22 @@ _file_try_punch_hole (int fd, gsize offset, gsize len)
{
#ifndef VTESTREAM_MAIN
# ifdef FALLOC_FL_PUNCH_HOLE
+ static int n = 0;
+
if (G_UNLIKELY (fd == -1))
return FALSE;
/* Punching hole is slow for me (Linux 3.16, ext4),
* causing a ~10% overall performance regression.
- * Disable it for now. */
- /* fallocate (fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len); */
+ * On the other hand, it's required to see benefits from
+ * compression in the finite scrollback case, without this
+ * a smaller (better compressed) block will only overwrite
+ * the first part of a larger (less compressed) block.
+ * As a compromise, punch hole "randomly" with 1/16 chance.
+ * TODOegmont: This is still very slow for me, no clue why. */
+ if (G_UNLIKELY ((n++ & 0x0F) == 0)) {
+ fallocate (fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len);
+ }
return TRUE;
# else
@@ -293,7 +319,7 @@ typedef struct _VteSnakeClass {
GObjectClass parent_class;
void (*reset) (VteSnake *snake, gsize offset);
- void (*write) (VteSnake *snake, gsize offset, const char *data);
+ void (*write) (VteSnake *snake, gsize offset, const char *data, gsize len);
gboolean (*read) (VteSnake *snake, gsize offset, char *data);
void (*advance_tail) (VteSnake *snake, gsize offset);
gsize (*tail) (VteSnake *snake);
@@ -389,7 +415,7 @@ _vte_snake_read (VteSnake *snake, gsize offset, char *data)
* 1->2, 2->3.
*/
static void
-_vte_snake_write (VteSnake *snake, gsize offset, const char *data)
+_vte_snake_write (VteSnake *snake, gsize offset, const char *data, gsize len)
{
gsize fd_offset;
@@ -422,6 +448,15 @@ _vte_snake_write (VteSnake *snake, gsize offset, const char *data)
snake->segment[last_segment].st_head += VTE_SNAKE_BLOCKSIZE;
snake->segment[last_segment].fd_head += VTE_SNAKE_BLOCKSIZE;
}
+ if (snake->state != 2) {
+ /* Grow the file with sparse blocks to make sure that later pread() can
+ * read back a whole block, even if we are about to write a shorter one. */
+ _file_try_truncate (snake->fd, fd_offset + VTE_SNAKE_BLOCKSIZE);
+#ifdef VTESTREAM_MAIN
+ /* For convenient unit testing only: fill with dots. */
+ _file_try_punch_hole (snake->fd, fd_offset, VTE_SNAKE_BLOCKSIZE);
+#endif
+ }
snake->head = offset + VTE_SNAKE_BLOCKSIZE;
} else {
/* Overwriting an existing block. The new block might be shorter than the old one,
@@ -429,7 +464,7 @@ _vte_snake_write (VteSnake *snake, gsize offset, const char *data)
fd_offset = _vte_snake_offset_map(snake, offset);
_file_try_punch_hole (snake->fd, fd_offset, VTE_SNAKE_BLOCKSIZE);
}
- _file_write (snake->fd, data, VTE_SNAKE_BLOCKSIZE, fd_offset);
+ _file_write (snake->fd, data, len, fd_offset);
}
/*
@@ -518,13 +553,255 @@ _vte_snake_class_init (VteSnakeClass *klass)
/******************************************************************************************/
/*
- * VteFileStream: Implement buffering/caching on top of VteSnake.
+ * VteBoa: Compress the data.
+ *
+ * The data is stored as 4 bytes (1 byte for unit testing) denoting the length
+ * of the compressed block, followed by the compressed data. The data is
+ * stored uncompressed if compression didn't result in a smaller size.
+ */
+
+typedef struct _VteBoa {
+ VteSnake parent;
+ gsize tail, head;
+
+ int compressBound;
+} VteBoa;
+
+typedef struct _VteBoaClass {
+ GObjectClass parent_class;
+
+ void (*reset) (VteBoa *boa, gsize offset);
+ void (*write) (VteBoa *boa, gsize offset, const char *data);
+ gboolean (*read) (VteBoa *boa, gsize offset, char *data);
+ void (*advance_tail) (VteBoa *boa, gsize offset);
+ gsize (*tail) (VteBoa *boa);
+ gsize (*head) (VteBoa *boa);
+} VteBoaClass;
+
+static GType _vte_boa_get_type (void);
+#define VTE_TYPE_BOA _vte_boa_get_type ()
+#define VTE_BOA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VTE_TYPE_BOA, VteBoaClass))
+
+G_DEFINE_TYPE (VteBoa, _vte_boa, VTE_TYPE_SNAKE)
+
+/*----------------------------------------------------------------------------------------*/
+
+/* Thin wrapper layers above the compression routines, for unit testing. */
+
+static int
+_vte_boa_compressBound (unsigned int len)
+{
+#ifndef VTESTREAM_MAIN
+ return compressBound(len);
+#else
+ return 2 * len;
+#endif
+}
+
+/* Compress; returns the compressed size which might be bigger than the original. */
+static unsigned int
+_vte_boa_compress (char *dst, unsigned int dstlen, const char *src, unsigned int srclen)
+{
+#ifndef VTESTREAM_MAIN
+ uLongf dstlen_ulongf = dstlen;
+ g_assert_cmpuint (compress2 ((Bytef *) dst, &dstlen_ulongf, (const Bytef *) src, srclen, 1), ==,
Z_OK);
+ return dstlen_ulongf;
+#else
+ /* Fake compression for unit testing:
+ * Each char gets prefixed by a repetition count. This prefix is omitted if it would be the
+ * same as the previous.
+ * E.g. abcdef <-> 1abcdef
+ * www <-> 3w
+ * Mississippi <-> 1Mi2s1i2s1i2p1i
+ * bookkeeper <-> 1b2oke1per
+ * The uncompressed string shouldn't contain digits, or more than 9 consecutive identical chars.
+ */
+ unsigned int len = 0, prevrepeat = 0;
+ while (srclen) {
+ unsigned int repeat = 1;
+ while (repeat < srclen && src[repeat] == src[0]) repeat++;
+ if (repeat != prevrepeat) {
+ *dst++ = '0' + repeat;
+ prevrepeat = repeat;
+ len++;
+ }
+ *dst++ = src[0];
+ src += repeat, srclen -= repeat;
+ len++;
+ }
+ return len;
+#endif
+}
+
+/* Uncompress; returns the uncompressed size. */
+static unsigned int
+_vte_boa_uncompress (char *dst, unsigned int dstlen, const char *src, unsigned int srclen)
+{
+#ifndef VTESTREAM_MAIN
+ uLongf dstlen_ulongf = dstlen;
+ g_assert_cmpuint (uncompress ((Bytef *) dst, &dstlen_ulongf, (const Bytef *) src, srclen), ==, Z_OK);
+ return dstlen_ulongf;
+#else
+ /* Fake decompression for unit testing; see above. */
+ unsigned int len = 0, repeat = 0;
+ while (srclen) {
+ unsigned char c = *src;
+ if (c >= '0' && c <= '9') {
+ repeat = c - '0';
+ } else {
+ memset (dst, c, repeat);
+ dst += repeat, len += repeat;
+ }
+ src++; srclen--;
+ }
+ return len;
+#endif
+}
+
+/*----------------------------------------------------------------------------------------*/
+
+static void
+_vte_boa_init (VteBoa *boa)
+{
+ boa->compressBound = _vte_boa_compressBound(VTE_BOA_BLOCKSIZE);
+}
+
+static void
+_vte_boa_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (_vte_boa_parent_class)->finalize(object);
+}
+
+static void
+_vte_boa_reset (VteBoa *boa, gsize offset)
+{
+ g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
+
+ _vte_snake_reset (&boa->parent, OFFSET_BOA_TO_SNAKE(offset));
+
+ boa->tail = boa->head = offset;
+}
+
+/* Place VTE_BOA_BLOCKSIZE bytes at data. */
+static gboolean
+_vte_boa_read (VteBoa *boa, gsize offset, char *data)
+{
+ _vte_block_datalength_t compressed_len;
+ gboolean ret = FALSE;
+ char *buf = g_malloc(VTE_SNAKE_BLOCKSIZE);
+
+ g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
+
+ /* Read */
+ if (G_UNLIKELY (!_vte_snake_read (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), buf)))
+ goto out;
+
+ compressed_len = *((_vte_block_datalength_t *) buf);
+
+ /* We could have read an empty block due to a previous disk full. Treat that as an error too.
Perform other sanity checks. */
+ if (G_UNLIKELY (compressed_len <= 0 || compressed_len > VTE_BOA_BLOCKSIZE))
+ goto out;
+
+ /* Uncompress, or copy if wasn't compressable */
+ if (G_UNLIKELY (compressed_len >= VTE_BOA_BLOCKSIZE)) {
+ memcpy (data, buf + VTE_BLOCK_DATALENGTH_SIZE, VTE_BOA_BLOCKSIZE);
+ } else {
+ g_assert_cmpuint (_vte_boa_uncompress(data, VTE_BOA_BLOCKSIZE, buf +
VTE_BLOCK_DATALENGTH_SIZE, compressed_len), ==, VTE_BOA_BLOCKSIZE);
+ }
+ ret = TRUE;
+
+out:
+ g_free(buf);
+ return ret;
+}
+
+/*
+ * offset is either within the stream (overwrite data), or at its head (append data).
+ * data is VTE_BOA_BLOCKSIZE bytes large.
+ */
+static void
+_vte_boa_write (VteBoa *boa, gsize offset, const char *data)
+{
+ _vte_block_datalength_t compressed_len = boa->compressBound;
+
+ /* The helper buffer should be large enough to contain a whole snake block,
+ * and also large enough to compress data that actually grows bigger during compression. */
+ char *buf = g_malloc(MAX(VTE_SNAKE_BLOCKSIZE,
+ VTE_BLOCK_DATALENGTH_SIZE + boa->compressBound));
+
+ g_assert_cmpuint (offset, >=, boa->tail);
+ g_assert_cmpuint (offset, <=, boa->head);
+ g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
+
+ /* Compress, or copy if uncompressable */
+ compressed_len = _vte_boa_compress (buf + VTE_BLOCK_DATALENGTH_SIZE, boa->compressBound,
+ data, VTE_BOA_BLOCKSIZE);
+ if (G_UNLIKELY (compressed_len >= VTE_BOA_BLOCKSIZE)) {
+ memcpy (buf + VTE_BLOCK_DATALENGTH_SIZE, data, VTE_BOA_BLOCKSIZE);
+ compressed_len = VTE_BOA_BLOCKSIZE;
+ }
+
+ *((_vte_block_datalength_t *) buf) = (_vte_block_datalength_t) compressed_len;
+
+ /* Write */
+ _vte_snake_write (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), buf, VTE_BLOCK_DATALENGTH_SIZE +
compressed_len);
+
+ if (G_LIKELY (offset == boa->head)) {
+ boa->head += VTE_BOA_BLOCKSIZE;
+ }
+
+ g_free(buf);
+}
+
+static void
+_vte_boa_advance_tail (VteBoa *boa, gsize offset)
+{
+ g_assert_cmpuint (offset, >=, boa->tail);
+ g_assert_cmpuint (offset, <=, boa->head);
+ g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
+
+ _vte_snake_advance_tail (&boa->parent, OFFSET_BOA_TO_SNAKE(offset));
+
+ boa->tail = offset;
+}
+
+static gsize
+_vte_boa_tail (VteBoa *boa)
+{
+ return boa->tail;
+}
+
+static gsize
+_vte_boa_head (VteBoa *boa)
+{
+ return boa->head;
+}
+
+static void
+_vte_boa_class_init (VteBoaClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = _vte_boa_finalize;
+
+ klass->reset = _vte_boa_reset;
+ klass->read = _vte_boa_read;
+ klass->write = _vte_boa_write;
+ klass->advance_tail = _vte_boa_advance_tail;
+ klass->tail = _vte_boa_tail;
+ klass->head = _vte_boa_head;
+}
+
+/******************************************************************************************/
+
+/*
+ * VteFileStream: Implement buffering/caching on top of VteBoa.
*/
typedef struct _VteFileStream {
GObject parent;
- VteSnake *snake;
+ VteBoa *boa;
char *rbuf;
/* Offset of the cached record, always a multiple of block size.
@@ -554,11 +831,11 @@ _vte_file_stream_new (void)
static void
_vte_file_stream_init (VteFileStream *stream)
{
- stream->snake = g_object_new (VTE_TYPE_SNAKE, NULL);
- _vte_snake_init (stream->snake);
+ stream->boa = g_object_new (VTE_TYPE_BOA, NULL);
+ _vte_boa_init (stream->boa);
- stream->rbuf = g_malloc(VTE_SNAKE_BLOCKSIZE);
- stream->wbuf = g_malloc(VTE_SNAKE_BLOCKSIZE);
+ stream->rbuf = g_malloc(VTE_BOA_BLOCKSIZE);
+ stream->wbuf = g_malloc(VTE_BOA_BLOCKSIZE);
stream->rbuf_offset = 1; /* Invalidate */
}
@@ -569,7 +846,7 @@ _vte_file_stream_finalize (GObject *object)
g_free(stream->rbuf);
g_free(stream->wbuf);
- g_object_unref (stream->snake);
+ g_object_unref (stream->boa);
G_OBJECT_CLASS (_vte_file_stream_parent_class)->finalize(object);
}
@@ -578,9 +855,9 @@ static void
_vte_file_stream_reset (VteStream *astream, gsize offset)
{
VteFileStream *stream = (VteFileStream *) astream;
- gsize offset_aligned = ALIGN_SNAKE(offset);
+ gsize offset_aligned = ALIGN_BOA(offset);
- _vte_snake_reset (stream->snake, offset_aligned);
+ _vte_boa_reset (stream->boa, offset_aligned);
stream->tail = stream->head = offset;
/* When resetting at a non-aligned offset, initial bytes of the write buffer
@@ -588,12 +865,12 @@ _vte_file_stream_reset (VteStream *astream, gsize offset)
* Rather than leaving garbage there, fill it with zeros.
* For unit testing, fill it with dashes for convenience. */
#ifndef VTESTREAM_MAIN
- memset(stream->wbuf, 0, MOD_SNAKE(offset));
+ memset(stream->wbuf, 0, MOD_BOA(offset));
#else
- memset(stream->wbuf, '-', MOD_SNAKE(offset));
+ memset(stream->wbuf, '-', MOD_BOA(offset));
#endif
- stream->wbuf_len = MOD_SNAKE(offset);
+ stream->wbuf_len = MOD_BOA(offset);
stream->rbuf_offset = 1; /* Invalidate */
}
@@ -617,20 +894,20 @@ _vte_file_stream_read (VteStream *astream, gsize offset, char *data, gsize len)
g_assert_not_reached();
}
- while (len && offset < ALIGN_SNAKE(stream->head)) {
- gsize l = MIN(VTE_SNAKE_BLOCKSIZE - MOD_SNAKE(offset), len);
- gsize offset_aligned = ALIGN_SNAKE(offset);
+ while (len && offset < ALIGN_BOA(stream->head)) {
+ gsize l = MIN(VTE_BOA_BLOCKSIZE - MOD_BOA(offset), len);
+ gsize offset_aligned = ALIGN_BOA(offset);
if (offset_aligned != stream->rbuf_offset) {
- if (G_UNLIKELY (!_vte_snake_read (stream->snake, offset_aligned, stream->rbuf)))
+ if (G_UNLIKELY (!_vte_boa_read (stream->boa, offset_aligned, stream->rbuf)))
return FALSE;
stream->rbuf_offset = offset_aligned;
}
- memcpy(data, stream->rbuf + MOD_SNAKE(offset), l);
+ memcpy(data, stream->rbuf + MOD_BOA(offset), l);
offset += l; data += l; len -= l;
}
if (len) {
- g_assert_cmpuint (MOD_SNAKE(offset) + len, <=, stream->wbuf_len);
- memcpy(data, stream->wbuf + MOD_SNAKE(offset), len);
+ g_assert_cmpuint (MOD_BOA(offset) + len, <=, stream->wbuf_len);
+ memcpy(data, stream->wbuf + MOD_BOA(offset), len);
}
return TRUE;
}
@@ -641,11 +918,11 @@ _vte_file_stream_append (VteStream *astream, const char *data, gsize len)
VteFileStream *stream = (VteFileStream *) astream;
while (len) {
- gsize l = MIN(VTE_SNAKE_BLOCKSIZE - stream->wbuf_len, len);
+ gsize l = MIN(VTE_BOA_BLOCKSIZE - stream->wbuf_len, len);
memcpy(stream->wbuf + stream->wbuf_len, data, l);
stream->wbuf_len += l; data += l; len -= l;
- if (stream->wbuf_len == VTE_SNAKE_BLOCKSIZE) {
- _vte_snake_write (stream->snake, ALIGN_SNAKE(stream->head), stream->wbuf);
+ if (stream->wbuf_len == VTE_BOA_BLOCKSIZE) {
+ _vte_boa_write (stream->boa, ALIGN_BOA(stream->head), stream->wbuf);
stream->wbuf_len = 0;
}
stream->head += l;
@@ -660,24 +937,24 @@ _vte_file_stream_truncate (VteStream *astream, gsize offset)
g_assert_cmpuint (offset, >=, stream->tail);
g_assert_cmpuint (offset, <=, stream->head);
- if (offset < ALIGN_SNAKE(stream->head)) {
+ if (offset < ALIGN_BOA(stream->head)) {
/* Truncating goes back to the part that we've written to the
* file. For simplicity (since this is a rare event, only
* happens when the window size changes) go for the simplest
* local hack here that allows to leave the rest of the code
* intact, that is, read back the new partial last block to
* the write cache. */
- gsize offset_aligned = ALIGN_SNAKE(offset);
- if (G_UNLIKELY (!_vte_snake_read (stream->snake, offset_aligned, stream->wbuf))) {
+ gsize offset_aligned = ALIGN_BOA(offset);
+ if (G_UNLIKELY (!_vte_boa_read (stream->boa, offset_aligned, stream->wbuf))) {
/* what now? */
- memset(stream->wbuf, 0, VTE_SNAKE_BLOCKSIZE);
+ memset(stream->wbuf, 0, VTE_BOA_BLOCKSIZE);
}
if (stream->rbuf_offset >= offset_aligned) {
stream->rbuf_offset = 1; /* Invalidate */
}
}
- stream->wbuf_len = MOD_SNAKE(offset);
+ stream->wbuf_len = MOD_BOA(offset);
stream->head = offset;
}
@@ -689,8 +966,8 @@ _vte_file_stream_advance_tail (VteStream *astream, gsize offset)
g_assert_cmpuint (offset, >=, stream->tail);
g_assert_cmpuint (offset, <=, stream->head);
- if (ALIGN_SNAKE(offset) > ALIGN_SNAKE(stream->tail))
- _vte_snake_advance_tail (stream->snake, ALIGN_SNAKE(offset));
+ if (ALIGN_BOA(offset) > ALIGN_BOA(stream->tail))
+ _vte_boa_advance_tail (stream->boa, ALIGN_BOA(offset));
stream->tail = offset;
}
@@ -755,6 +1032,19 @@ _vte_file_stream_class_init (VteFileStreamClass *klass)
} \
} while (0)
+/* Check for the boa's tail, head and contents */
+#define assert_boa(__boa, __tail, __head, __contents) do { \
+ char __buf[VTE_BOA_BLOCKSIZE]; \
+ int __i; \
+ g_assert_cmpuint (boa->tail, ==, __tail); \
+ g_assert_cmpuint (boa->head, ==, __head); \
+ g_assert_cmpuint (strlen(__contents), ==, __head - __tail); \
+ for (__i = __tail; __i < __head; __i += VTE_BOA_BLOCKSIZE) { \
+ g_assert (_vte_boa_read (boa, __i, __buf)); \
+ g_assert (memcmp(__buf, __contents + __i - __tail, VTE_BOA_BLOCKSIZE) == 0); \
+ } \
+} while (0)
+
/* Check for the stream's tail, head and contents */
#define assert_stream(__astream, __tail, __head, __contents) do { \
char __buf[100]; \
@@ -765,147 +1055,270 @@ _vte_file_stream_class_init (VteFileStreamClass *klass)
g_assert (memcmp(__buf, __contents, __head - __tail) == 0); \
} while (0)
+/* Test the fake encryption/decryption and compression/decompression routines.
+ * It usually doesn't make too much sense to test something that's part of the test infrastructure,
+ * but if anything goes wrong we'd better catch it here rather than in the way more complicated tests. */
+static void
+test_fakes (void)
+{
+ char buf[100], buf2[100];
+ VteBoa *boa = g_object_new (VTE_TYPE_BOA, NULL);
+
+ /* Compress, but becomes bigger */
+ strcpy(buf, "abcdef");
+ g_assert_cmpuint(_vte_boa_compress (buf2, 100, buf, 6), ==, 7);
+ g_assert(strncmp (buf2, "1abcdef", 7) == 0);
+
+ /* Uncompress */
+ strcpy(buf, "1abcdef");
+ g_assert_cmpuint(_vte_boa_uncompress (buf2, 100, buf, 7), ==, 6);
+ g_assert(strncmp (buf2, "abcdef", 6) == 0);
+
+ /* Compress, becomes smaller */
+ strcpy(buf, "www");
+ g_assert_cmpuint(_vte_boa_compress (buf2, 100, buf, 3), ==, 2);
+ g_assert(strncmp (buf2, "3w", 2) == 0);
+
+ /* Uncompress */
+ strcpy(buf, "3w");
+ g_assert_cmpuint(_vte_boa_uncompress (buf2, 100, buf, 2), ==, 3);
+ g_assert(strncmp (buf2, "www", 3) == 0);
+
+ /* Compress, remains the same size */
+ strcpy(buf, "zebraaa");
+ g_assert_cmpuint(_vte_boa_compress (buf2, 100, buf, 7), ==, 7);
+ g_assert(strncmp (buf2, "1zebr3a", 7) == 0);
+
+ /* Uncompress */
+ strcpy(buf, "1zebr3a");
+ g_assert_cmpuint(_vte_boa_uncompress (buf2, 100, buf, 7), ==, 7);
+ g_assert(strncmp (buf2, "zebraaa", 7) == 0);
+
+ /* Trying to uncompress the original does *not* give back the same contents.
+ * This will be important below. */
+ strcpy(buf, "zebraaa");
+ g_assert_cmpuint(_vte_boa_uncompress (buf2, 100, buf, 7), ==, 0);
+
+ g_object_unref (boa);
+}
+
+#define snake_write(snake, offset, str) _vte_snake_write((snake), (offset), (str), strlen(str))
+
static void
test_snake (void)
{
VteSnake *snake = g_object_new (VTE_TYPE_SNAKE, NULL);
/* Test overwriting data */
- _vte_snake_write (snake, 0, "Alpaca.");
- assert_snake (snake, 1, 0, 7, "Alpaca.");
+ snake_write (snake, 0, "Antelope");
+ assert_snake (snake, 1, 0, 8, "Antelope");
- _vte_snake_write (snake, 7, "Bobcat.");
- assert_file (snake->fd, "Alpaca.Bobcat.");
- assert_snake (snake, 1, 0, 14, "Alpaca.Bobcat.");
+ snake_write (snake, 8, "Bobcat");
+ assert_file (snake->fd, "AntelopeBobcat..");
+ assert_snake (snake, 1, 0, 16, "AntelopeBobcat..");
- _vte_snake_write (snake, 7, "Camel..");
- assert_file (snake->fd, "Alpaca.Camel..");
- assert_snake (snake, 1, 0, 14, "Alpaca.Camel..");
+ snake_write (snake, 8, "Camel");
+ assert_file (snake->fd, "AntelopeCamel...");
+ assert_snake (snake, 1, 0, 16, "AntelopeCamel...");
- _vte_snake_write (snake, 0, "Duck...");
- assert_file (snake->fd, "Duck...Camel..");
- assert_snake (snake, 1, 0, 14, "Duck...Camel..");
+ snake_write (snake, 0, "Duck");
+ assert_file (snake->fd, "Duck....Camel...");
+ assert_snake (snake, 1, 0, 16, "Duck....Camel...");
- _vte_snake_write (snake, 14, ".......");
- assert_file (snake->fd, "Duck...Camel.........");
- assert_snake (snake, 1, 0, 21, "Duck...Camel.........");
+ snake_write (snake, 16, "");
+ assert_file (snake->fd, "Duck....Camel...........");
+ assert_snake (snake, 1, 0, 24, "Duck....Camel...........");
- _vte_snake_write (snake, 21, "Ferret.");
- assert_file (snake->fd, "Duck...Camel.........Ferret.");
- assert_snake (snake, 1, 0, 28, "Duck...Camel.........Ferret.");
+ snake_write (snake, 24, "Ferret");
+ assert_file (snake->fd, "Duck....Camel...........Ferret..");
+ assert_snake (snake, 1, 0, 32, "Duck....Camel...........Ferret..");
/* Reset */
_vte_snake_reset (snake, 0);
assert_snake (snake, 1, 0, 0, "");
/* State 1 */
- _vte_snake_write (snake, 0, "Alpaca.");
- _vte_snake_write (snake, 7, "Bobcat.");
- assert_file (snake->fd, "Alpaca.Bobcat.");
- assert_snake (snake, 1, 0, 14, "Alpaca.Bobcat.");
+ snake_write (snake, 0, "Antelope");
+ snake_write (snake, 8, "Bobcat");
+ assert_file (snake->fd, "AntelopeBobcat..");
+ assert_snake (snake, 1, 0, 16, "AntelopeBobcat..");
/* Stay in state 1 */
- _vte_snake_advance_tail (snake, 7);
- _vte_snake_write (snake, 14, "Camel..");
- assert_file (snake->fd, ".......Bobcat.Camel..");
- assert_snake (snake, 1, 7, 21, "Bobcat.Camel..");
+ _vte_snake_advance_tail (snake, 8);
+ snake_write (snake, 16, "Camel");
+ assert_file (snake->fd, "........Bobcat..Camel...");
+ assert_snake (snake, 1, 8, 24, "Bobcat..Camel...");
/* State 1 -> 2 */
- _vte_snake_advance_tail (snake, 14);
- _vte_snake_write (snake, 21, "Duck...");
- assert_file (snake->fd, "Duck..........Camel..");
- assert_snake (snake, 2, 14, 28, "Camel..Duck...");
+ _vte_snake_advance_tail (snake, 16);
+ snake_write (snake, 24, "Duck");
+ assert_file (snake->fd, "Duck............Camel...");
+ assert_snake (snake, 2, 16, 32, "Camel...Duck....");
/* Stay in state 2 */
- _vte_snake_write (snake, 28, "Eagle..");
- assert_file (snake->fd, "Duck...Eagle..Camel..");
- assert_snake (snake, 2, 14, 35, "Camel..Duck...Eagle..");
+ snake_write (snake, 32, "Elephant");
+ assert_file (snake->fd, "Duck....ElephantCamel...");
+ assert_snake (snake, 2, 16, 40, "Camel...Duck....Elephant");
/* State 2 -> 3 */
- _vte_snake_write (snake, 35, "Ferret.");
- assert_file (snake->fd, "Duck...Eagle..Camel..Ferret.");
- assert_snake (snake, 3, 14, 42, "Camel..Duck...Eagle..Ferret.");
+ snake_write (snake, 40, "Ferret");
+ assert_file (snake->fd, "Duck....ElephantCamel...Ferret..");
+ assert_snake (snake, 3, 16, 48, "Camel...Duck....ElephantFerret..");
/* State 3 -> 4 */
- _vte_snake_advance_tail (snake, 21);
- assert_file (snake->fd, "Duck...Eagle.........Ferret.");
- assert_snake (snake, 4, 21, 42, "Duck...Eagle..Ferret.");
+ _vte_snake_advance_tail (snake, 24);
+ assert_file (snake->fd, "Duck....Elephant........Ferret..");
+ assert_snake (snake, 4, 24, 48, "Duck....ElephantFerret..");
/* Stay in state 4 */
- _vte_snake_advance_tail (snake, 28);
- assert_file (snake->fd, ".......Eagle.........Ferret.");
- assert_snake (snake, 4, 28, 42, "Eagle..Ferret.");
+ _vte_snake_advance_tail (snake, 32);
+ assert_file (snake->fd, "........Elephant........Ferret..");
+ assert_snake (snake, 4, 32, 48, "ElephantFerret..");
/* State 4 -> 1 */
- _vte_snake_advance_tail (snake, 35);
- assert_file (snake->fd, ".....................Ferret.");
- assert_snake (snake, 1, 35, 42, "Ferret.");
+ _vte_snake_advance_tail (snake, 40);
+ assert_file (snake->fd, "........................Ferret..");
+ assert_snake (snake, 1, 40, 48, "Ferret..");
/* State 1 -> 2 */
- _vte_snake_write (snake, 42, "Giraffe");
- assert_file (snake->fd, "Giraffe..............Ferret.");
- assert_snake (snake, 2, 35, 49, "Ferret.Giraffe");
+ snake_write (snake, 48, "Giraffe");
+ assert_file (snake->fd, "Giraffe.................Ferret..");
+ assert_snake (snake, 2, 40, 56, "Ferret..Giraffe.");
/* Reset, back to state 1 */
- _vte_snake_reset (snake, 175);
- assert_snake (snake, 1, 175, 175, "");
+ _vte_snake_reset (snake, 200);
+ assert_snake (snake, 1, 200, 200, "");
/* Stay in state 1 */
- _vte_snake_write (snake, 175, "Zebra..");
- assert_file (snake->fd, "Zebra..");
- assert_snake (snake, 1, 175, 182, "Zebra..");
+ snake_write (snake, 200, "Zebra");
+ assert_file (snake->fd, "Zebra...");
+ assert_snake (snake, 1, 200, 208, "Zebra...");
g_object_unref (snake);
}
+static void
+test_boa (void)
+{
+ VteBoa *boa = g_object_new (VTE_TYPE_BOA, NULL);
+ VteSnake *snake = (VteSnake *) &boa->parent;
+
+ /* State 1 */
+ _vte_boa_write (boa, 0, "axolotl");
+ _vte_boa_write (boa, 7, "beeeeee");
+ assert_file (snake->fd, "\007axolotl" "\0041b6e...");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeee");
+
+ /* Test overwrites */
+ _vte_boa_write (boa, 7, "buffalo");
+ assert_file (snake->fd, "\007axolotl" "\007buffalo");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\007buffalo");
+ assert_boa (boa, 0, 14, "axolotl" "buffalo");
+
+ _vte_boa_write (boa, 7, "beeeeee");
+ assert_file (snake->fd, "\007axolotl" "\0041b6e...");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeee");
+
+ _vte_boa_write (boa, 0, "axolotl");
+ assert_file (snake->fd, "\007axolotl" "\0041b6e...");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeee");
+
+ /* Stay in state 1 */
+ _vte_boa_advance_tail (boa, 7);
+ _vte_boa_write (boa, 14, "cheetah");
+ assert_file (snake->fd, "........" "\0041b6e..." "\007cheetah");
+ assert_snake (snake, 1, 8, 24, "\0041b6e..." "\007cheetah");
+ assert_boa (boa, 7, 21, "beeeeee" "cheetah");
+
+ /* State 1 -> 2 */
+ _vte_boa_advance_tail (boa, 14);
+ _vte_boa_write (boa, 21, "deeeeer");
+ assert_file (snake->fd, "\0061d5e1r." "........" "\007cheetah");
+ assert_snake (snake, 2, 16, 32, "\007cheetah" "\0061d5e1r.");
+ assert_boa (boa, 14, 28, "cheetah" "deeeeer");
+
+ /* Skip some state changes that we tested in test_snake() */
+
+ /* Reset, back to state 1 */
+ _vte_boa_reset (boa, 175);
+ assert_snake (snake, 1, 200, 200, "");
+ assert_boa (boa, 175, 175, "");
+
+ /* Stay in state 1.
+ * Test handling a string that compresses exactly to its original,
+ * length, making sure that the uncompressed version is stored.
+ * It was tested above that trying to decompress the uncompressed
+ * version wouldn't work, so with this test we can be sure that we
+ * don't try to decompress.
+ */
+ _vte_boa_write (boa, 175, "zebraaa");
+ assert_file (snake->fd, "\007zebraaa");
+ assert_snake (snake, 1, 200, 208, "\007zebraaa");
+ assert_boa (boa, 175, 182, "zebraaa");
+
+ g_object_unref (boa);
+}
+
#define stream_append(as, str) _vte_stream_append((as), (str), strlen(str))
static void
test_stream (void)
{
+ VteBoa *boa;
VteSnake *snake;
char buf[8];
VteStream *astream = _vte_file_stream_new();
VteFileStream *stream = (VteFileStream *) astream;
_vte_file_stream_init (stream);
- snake = stream->snake;
+ boa = stream->boa;
+ snake = (VteSnake *) &boa->parent;
/* Append */
stream_append (astream, "axolot");
g_assert (snake->fd == -1);
+ assert_boa (boa, 0, 0, "");
assert_stream (astream, 0, 6, "axolot");
stream_append (astream, "l");
- assert_file (snake->fd, "axolotl");
- assert_snake (snake, 1, 0, 7, "axolotl");
+ assert_file (snake->fd, "\007axolotl");
+ assert_snake (snake, 1, 0, 8, "\007axolotl");
+ assert_boa (boa, 0, 7, "axolotl");
assert_stream (astream, 0, 7, "axolotl");
stream_append (astream, "beeee");
- assert_file (snake->fd, "axolotl");
- assert_snake (snake, 1, 0, 7, "axolotl");
+ assert_file (snake->fd, "\007axolotl");
+ assert_snake (snake, 1, 0, 8, "\007axolotl");
+ assert_boa (boa, 0, 7, "axolotl");
assert_stream (astream, 0, 12, "axolotl" "beeee");
stream_append (astream, "es" "cat");
- assert_file (snake->fd, "axolotl" "beeeees");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeees");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeees");
assert_stream (astream, 0, 17, "axolotl" "beeeees" "cat");
/* Truncate */
_vte_stream_truncate (astream, 14);
- assert_file (snake->fd, "axolotl" "beeeees");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeees");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeees");
assert_stream (astream, 0, 14, "axolotl" "beeeees");
_vte_stream_truncate (astream, 10);
- assert_file (snake->fd, "axolotl" "beeeees");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeees");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeees");
assert_stream (astream, 0, 10, "axolotl" "bee");
/* Increase overwrite counter, overwrite with shorter block */
stream_append (astream, "eeee" "cat");
- assert_file (snake->fd, "axolotl" "beeeeee");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeeee");
+ assert_file (snake->fd, "\007axolotl" "\0041b6e...");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+ assert_boa (boa, 0, 14, "axolotlbeeeeee");
assert_stream (astream, 0, 17, "axolotl" "beeeeee" "cat");
/* Test that the read cache is invalidated on truncate */
@@ -918,120 +1331,139 @@ test_stream (void)
g_assert_cmpuint (stream->rbuf_offset, ==, 7);
buf[2] = '\0';
g_assert_cmpstr (buf, ==, "ez");
- assert_file (snake->fd, "axolotl" "beeeeez");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeeez");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeez");
assert_stream (astream, 0, 17, "axolotl" "beeeeez" "cat");
/* Truncate again */
_vte_stream_truncate (astream, 10);
- assert_file (snake->fd, "axolotl" "beeeeez");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeeez");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeez");
assert_stream (astream, 0, 10, "axolotl" "bee");
/* Advance_tail */
_vte_stream_advance_tail (astream, 6);
- assert_file (snake->fd, "axolotl" "beeeeez");
- assert_snake (snake, 1, 0, 14, "axolotl" "beeeeez");
+ assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
+ assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+ assert_boa (boa, 0, 14, "axolotl" "beeeeez");
assert_stream (astream, 6, 10, "l" "bee");
_vte_stream_advance_tail (astream, 7);
- assert_file (snake->fd, "......." "beeeeez");
- assert_snake (snake, 1, 7, 14, "beeeeez");
+ assert_file (snake->fd, "........" "\0061b5e1z.");
+ assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+ assert_boa (boa, 7, 14, "beeeeez");
assert_stream (astream, 7, 10, "bee");
/* Tail and head within the same block in the stream,
* but not in underlying layers (due to a previous truncate).
* Nothing special. */
_vte_stream_advance_tail (astream, 9);
- assert_file (snake->fd, "......." "beeeeez");
- assert_snake (snake, 1, 7, 14, "beeeeez");
+ assert_file (snake->fd, "........" "\0061b5e1z.");
+ assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+ assert_boa (boa, 7, 14, "beeeeez");
assert_stream (astream, 9, 10, "e");
/* Tail reaches head. Still nothing special. */
_vte_stream_advance_tail (astream, 10);
- assert_file (snake->fd, "......." "beeeeez");
- assert_snake (snake, 1, 7, 14, "beeeeez");
+ assert_file (snake->fd, "........" "\0061b5e1z.");
+ assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+ assert_boa (boa, 7, 14, "beeeeez");
assert_stream (astream, 10, 10, "");
/* Snake state 2 */
stream_append (astream, "eeee" "catfish");
_vte_stream_advance_tail (astream, 15);
stream_append (astream, "dolphin" "echi");
- assert_file (snake->fd, "dolphin" "......." "catfish");
- assert_snake (snake, 2, 14, 28, "catfish" "dolphin");
+ assert_file (snake->fd, "\007dolphin" "........" "\007catfish");
+ assert_snake (snake, 2, 16, 32, "\007catfish" "\007dolphin");
+ assert_boa (boa, 14, 28, "catfish" "dolphin");
assert_stream (astream, 15, 32, "atfish" "dolphin" "echi");
/* Tail and head within the same block.
* The snake resets itself to state 1, ...
* (Note: despite advance_tail, "ec" is still there in the write buffer) */
_vte_stream_advance_tail (astream, 30);
- assert_snake (snake, 1, 28, 28, "");
+ assert_snake (snake, 1, 32, 32, "");
+ assert_boa (boa, 28, 28, "");
assert_stream (astream, 30, 32, "hi");
/* ... and the next write goes to beginning of the file */
stream_append (astream, "dna");
- assert_file (snake->fd, "echidna");
- assert_snake (snake, 1, 28, 35, "echidna");
+ assert_file (snake->fd, "\007echidna");
+ assert_snake (snake, 1, 32, 40, "\007echidna");
+ assert_boa (boa, 28, 35, "echidna");
assert_stream (astream, 30, 35, "hidna");
/* Test a bit what happens when "accidentally" writing aligned blocks. */
_vte_stream_advance_tail (astream, 35);
stream_append (astream, "flicker" "grizzly");
- assert_file (snake->fd, "flicker" "grizzly");
- assert_snake (snake, 1, 35, 49, "flicker" "grizzly");
+ assert_file (snake->fd, "\007flicker" "\007grizzly");
+ assert_snake (snake, 1, 40, 56, "\007flicker" "\007grizzly");
+ assert_boa (boa, 35, 49, "flicker" "grizzly");
assert_stream (astream, 35, 49, "flicker" "grizzly");
stream_append (astream, "hamster");
- assert_file (snake->fd, "flicker" "grizzly" "hamster");
- assert_snake (snake, 1, 35, 56, "flicker" "grizzly" "hamster");
+ assert_file (snake->fd, "\007flicker" "\007grizzly" "\007hamster");
+ assert_snake (snake, 1, 40, 64, "\007flicker" "\007grizzly" "\007hamster");
+ assert_boa (boa, 35, 56, "flicker" "grizzly" "hamster");
assert_stream (astream, 35, 56, "flicker" "grizzly" "hamster");
_vte_stream_advance_tail (astream, 49);
- assert_file (snake->fd, "......." "......." "hamster");
- assert_snake (snake, 1, 49, 56, "hamster");
+ assert_file (snake->fd, "........" "........" "\007hamster");
+ assert_snake (snake, 1, 56, 64, "\007hamster");
+ assert_boa (boa, 49, 56, "hamster");
assert_stream (astream, 49, 56, "hamster");
/* State 2 */
stream_append (astream, "ibexxxx");
- assert_file (snake->fd, "ibexxxx" "......." "hamster");
- assert_snake (snake, 2, 49, 63, "hamster" "ibexxxx");
+ assert_file (snake->fd, "\0061ibe4x." "........" "\007hamster");
+ assert_snake (snake, 2, 56, 72, "\007hamster" "\0061ibe4x.");
+ assert_boa (boa, 49, 63, "hamster" "ibexxxx");
assert_stream (astream, 49, 63, "hamster" "ibexxxx");
stream_append (astream, "jjjjjjj");
- assert_file (snake->fd, "ibexxxx" "jjjjjjj" "hamster");
- assert_snake (snake, 2, 49, 70, "hamster" "ibexxxx" "jjjjjjj");
+ assert_file (snake->fd, "\0061ibe4x." "\0027j....." "\007hamster");
+ assert_snake (snake, 2, 56, 80, "\007hamster" "\0061ibe4x." "\0027j.....");
+ assert_boa (boa, 49, 70, "hamster" "ibexxxx" "jjjjjjj");
assert_stream (astream, 49, 70, "hamster" "ibexxxx" "jjjjjjj");
/* State 3 */
stream_append (astream, "karakul");
- assert_file (snake->fd, "ibexxxx" "jjjjjjj" "hamster" "karakul");
- assert_snake (snake, 3, 49, 77, "hamster" "ibexxxx" "jjjjjjj" "karakul");
+ assert_file (snake->fd, "\0061ibe4x." "\0027j....." "\007hamster" "\007karakul");
+ assert_snake (snake, 3, 56, 88, "\007hamster" "\0061ibe4x." "\0027j....." "\007karakul");
+ assert_boa (boa, 49, 77, "hamster" "ibexxxx" "jjjjjjj" "karakul");
assert_stream (astream, 49, 77, "hamster" "ibexxxx" "jjjjjjj" "karakul");
/* State 4 */
_vte_stream_advance_tail (astream, 56);
- assert_file (snake->fd, "ibexxxx" "jjjjjjj" "......." "karakul");
- assert_snake (snake, 4, 56, 77, "ibexxxx" "jjjjjjj" "karakul");
+ assert_file (snake->fd, "\0061ibe4x." "\0027j....." "........" "\007karakul");
+ assert_snake (snake, 4, 64, 88, "\0061ibe4x." "\0027j....." "\007karakul");
+ assert_boa (boa, 56, 77, "ibexxxx" "jjjjjjj" "karakul");
assert_stream (astream, 56, 77, "ibexxxx" "jjjjjjj" "karakul");
stream_append (astream, "llllama");
- assert_file (snake->fd, "ibexxxx" "jjjjjjj" "......." "karakul" "llllama");
- assert_snake (snake, 4, 56, 84, "ibexxxx" "jjjjjjj" "karakul" "llllama");
+ assert_file (snake->fd, "\0061ibe4x." "\0027j....." "........" "\007karakul" "\0064l1ama.");
+ assert_snake (snake, 4, 64, 96, "\0061ibe4x." "\0027j....." "\007karakul" "\0064l1ama.");
+ assert_boa (boa, 56, 84, "ibexxxx" "jjjjjjj" "karakul" "llllama");
assert_stream (astream, 56, 84, "ibexxxx" "jjjjjjj" "karakul" "llllama");
/* Explicit reset to the middle of a poor meerkat */
_vte_stream_reset (astream, 88);
stream_append (astream, "kat");
/* Unused leading blocks are filled with dashes */
- assert_file (snake->fd, "----kat");
- assert_snake (snake, 1, 84, 91, "----kat");
+ assert_file (snake->fd, "\0064-1kat.");
+ assert_snake (snake, 1, 96, 104, "\0064-1kat.");
+ assert_boa (boa, 84, 91, "----kat");
assert_stream (astream, 88, 91, "kat");
/* Explicit reset to a block boundary */
_vte_stream_reset (astream, 175);
stream_append (astream, "zebraaa");
- assert_file (snake->fd, "zebraaa");
- assert_snake (snake, 1, 175, 182, "zebraaa");
+ assert_file (snake->fd, "\007zebraaa");
+ assert_snake (snake, 1, 200, 208, "\007zebraaa");
+ assert_boa (boa, 175, 182, "zebraaa");
assert_stream (astream, 175, 182, "zebraaa");
g_object_unref (astream);
@@ -1040,7 +1472,10 @@ test_stream (void)
int
main (int argc, char **argv)
{
+ test_fakes();
+
test_snake();
+ test_boa();
test_stream();
printf("vtestream-file tests passed :)\n");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]