Exemplo n.º 1
0
static void
test_html (const char *datadir, const char *input, const char *output, guint32 citation)
{
	guint32 flags = GMIME_FILTER_HTML_CONVERT_NL | GMIME_FILTER_HTML_CONVERT_SPACES |
		GMIME_FILTER_HTML_CONVERT_URLS | GMIME_FILTER_HTML_CONVERT_ADDRESSES;
	const char *what = "GMimeFilterHtml", *mode;
	GByteArray *expected, *actual;
	GMimeStream *stream;
	GMimeFilter *filter;
	char *path;
	
	switch (citation) {
	case GMIME_FILTER_HTML_BLOCKQUOTE_CITATION: mode = "blockquote"; break;
	case GMIME_FILTER_HTML_MARK_CITATION: mode = "mark"; break;
	case GMIME_FILTER_HTML_CITE: mode = "cite"; break;
	default: mode = "none"; break;
	}
	
	testsuite_check ("%s (%s %s)", what, input, mode);
	
	actual = g_byte_array_new ();
	stream = g_mime_stream_mem_new_with_byte_array (actual);
	g_mime_stream_mem_set_owner ((GMimeStreamMem *) stream, FALSE);
	
	filter = g_mime_filter_html_new (flags | citation, 0x008888);
	
	path = g_build_filename (datadir, input, NULL);
	pump_data_through_filter (filter, path, stream, TRUE, TRUE);
	g_mime_filter_reset (filter);
	g_object_unref (stream);
	g_object_unref (filter);
	g_free (path);
	
	path = g_build_filename (datadir, output, NULL);
	expected = read_all_bytes (path, TRUE);
	g_free (path);
	
	if (actual->len != expected->len) {
		testsuite_check_failed ("%s failed: stream lengths do not match: expected=%u; actual=%u",
					what, expected->len, actual->len);
		stream = g_mime_stream_fs_open (output, O_WRONLY | O_CREAT, 0644, NULL);
		g_mime_stream_write (stream, (const char *) actual->data, actual->len);
		g_mime_stream_flush (stream);
		g_object_unref (stream);
		goto error;
	}
	
	if (memcmp (actual->data, expected->data, actual->len) != 0) {
		testsuite_check_failed ("%s failed: stream contents do not match", what);
		goto error;
	}
	
	testsuite_check_passed ();
	
error:
	
	g_byte_array_free (expected, TRUE);
	g_byte_array_free (actual, TRUE);
}
Exemplo n.º 2
0
void UcXmlParserTest::testSimpleParsing()
{
    void* pD = NULL;

    int nLen = read_all_bytes("..\\..\\..\\test\\test_pages\\lp_navi.xml", &pD);

    pXmlParser_m->parseData((const char*)pD, nLen, true);

    free_all_bytes(pD);
}
Exemplo n.º 3
0
bool load_image(flow_c * c, char * checksum, struct flow_bitmap_bgra ** ref, void * bitmap_owner)
{
    char filename[2048];
    if (!create_relative_path(c, false, filename, 2048, "/visuals/%s.png", checksum)) {
        FLOW_add_to_callstack(c);
        return false;
    }

    struct flow_job * job = flow_job_create(c);
    if (job == NULL) {
        FLOW_error_return(c);
    }
    size_t bytes_count;
    uint8_t * bytes = read_all_bytes(c, &bytes_count, filename);
    if (bytes == NULL) {
        FLOW_error_return(c);
    }
    struct flow_io * input = flow_io_create_from_memory(c, flow_io_mode_read_seekable, bytes, bytes_count, job, NULL);
    if (input == NULL) {
        FLOW_error_return(c);
    }
    if (!flow_job_add_io(c, job, input, 0, FLOW_INPUT)) {
        FLOW_error_return(c);
    }

    struct flow_graph * g = flow_graph_create(c, 10, 10, 200, 2.0);
    if (g == NULL) {
        FLOW_add_to_callstack(c);
        return false;
    }
    int32_t last;
    last = flow_node_create_decoder(c, &g, -1, 0);
    last = flow_node_create_bitmap_bgra_reference(c, &g, last, ref);

    if (flow_context_has_error(c)) {
        FLOW_add_to_callstack(c);
        return false;
    }
    if (!flow_job_execute(c, job, &g)) {
        FLOW_add_to_callstack(c);
        return false;
    }

    // Let the bitmap last longer than the job
    if (!flow_set_owner(c, *ref, bitmap_owner)) {
        FLOW_add_to_callstack(c);
        return false;
    }

    if (!flow_job_destroy(c, job)) {
        FLOW_error_return(c);
    }
    FLOW_free(c, bytes);
    return true;
}
Exemplo n.º 4
0
static void
test_gzip (const char *datadir, const char *filename)
{
	char *name = g_strdup_printf ("%s.gz", filename);
	char *path = g_build_filename (datadir, filename, NULL);
	const char *what = "GMimeFilterGzip::zip";
	GByteArray *actual, *expected;
	GMimeStream *stream;
	GMimeFilter *filter;
	
	testsuite_check ("%s", what);
	
	actual = g_byte_array_new ();
	stream = g_mime_stream_mem_new_with_byte_array (actual);
	g_mime_stream_mem_set_owner ((GMimeStreamMem *) stream, FALSE);
	
	filter = g_mime_filter_gzip_new (GMIME_FILTER_GZIP_MODE_ZIP, 9);
	g_mime_filter_gzip_set_filename ((GMimeFilterGZip *) filter, filename);
	g_mime_filter_gzip_set_comment ((GMimeFilterGZip *) filter, "This is a comment.");
	
	pump_data_through_filter (filter, path, stream, TRUE, TRUE);
	g_mime_filter_reset (filter);
	g_object_unref (stream);
	g_object_unref (filter);
	g_free (path);
	
	path = g_build_filename (datadir, name, NULL);
	expected = read_all_bytes (path, FALSE);
	g_free (name);
	g_free (path);
	
	if (actual->len != 1233 && (actual->len != expected->len || memcmp (actual->data, expected->data, actual->len) != 0)) {
		if (actual->len != expected->len)
			testsuite_check_failed ("%s failed: streams are not the same length: %u", what, actual->len);
		else
			testsuite_check_failed ("%s failed: streams do not match", what);
		
		name = g_strdup_printf ("%s.1.gz", filename);
		path = g_build_filename (datadir, name, NULL);
		g_free (name);
		
		stream = g_mime_stream_fs_open (path, O_WRONLY | O_CREAT | O_TRUNC, 0644, NULL);
		g_free (path);
		
		g_mime_stream_write (stream, (const char *) actual->data, actual->len);
		g_mime_stream_flush (stream);
		g_object_unref (stream);
	} else {
		testsuite_check_passed ();
	}
	
	g_byte_array_free (expected, TRUE);
	g_byte_array_free (actual, TRUE);
}
Exemplo n.º 5
0
static void
test_charset_conversion (const char *datadir, const char *base, const char *from, const char *to)
{
	const char *what = "GMimeFilterCharset";
	GByteArray *actual, *expected;
	GMimeStream *stream;
	GMimeFilter *filter;
	char *path, *name;
	
	testsuite_check ("%s (%s %s -> %s)", what, base, from, to);
	
	actual = g_byte_array_new ();
	stream = g_mime_stream_mem_new_with_byte_array (actual);
	g_mime_stream_mem_set_owner ((GMimeStreamMem *) stream, FALSE);
	
	filter = g_mime_filter_charset_new (from, to);
	
	name = g_strdup_printf ("%s.%s.txt", base, from);
	path = g_build_filename (datadir, name, NULL);
	pump_data_through_filter (filter, path, stream, TRUE, TRUE);
	g_mime_filter_reset (filter);
	g_object_unref (stream);
	g_object_unref (filter);
	g_free (path);
	g_free (name);
	
	name = g_strdup_printf ("%s.%s.txt", base, to);
	path = g_build_filename (datadir, name, NULL);
	expected = read_all_bytes (path, TRUE);
	g_free (path);
	g_free (name);
	
	if (actual->len != expected->len) {
		testsuite_check_failed ("%s failed: stream lengths do not match: expected=%u; actual=%u",
					what, expected->len, actual->len);
		goto error;
	}
	
	if (memcmp (actual->data, expected->data, actual->len) != 0) {
		testsuite_check_failed ("%s failed: stream contents do not match", what);
		goto error;
	}
	
	testsuite_check_passed ();
	
error:
	
	g_byte_array_free (expected, TRUE);
	g_byte_array_free (actual, TRUE);
}
Exemplo n.º 6
0
static void
test_enriched (const char *datadir, const char *input, const char *output)
{
	const char *what = "GMimeFilterEnriched";
	GByteArray *actual, *expected;
	GMimeStream *stream;
	GMimeFilter *filter;
	char *path;
	
	testsuite_check ("%s (%s)", what, input);
	
	actual = g_byte_array_new ();
	stream = g_mime_stream_mem_new_with_byte_array (actual);
	g_mime_stream_mem_set_owner ((GMimeStreamMem *) stream, FALSE);
	
	filter = g_mime_filter_enriched_new (0);
	
	path = g_build_filename (datadir, input, NULL);
	pump_data_through_filter (filter, path, stream, TRUE, TRUE);
	g_mime_filter_reset (filter);
	g_object_unref (stream);
	g_object_unref (filter);
	g_free (path);
	
	path = g_build_filename (datadir, output, NULL);
	expected = read_all_bytes (path, TRUE);
	g_free (path);
	
	if (actual->len != expected->len) {
		testsuite_check_failed ("%s failed: stream lengths do not match: expected=%u; actual=%u",
					what, expected->len, actual->len);
		printf ("enriched: -->%.*s<--\n", (int) actual->len, (char *) actual->data);
		goto error;
	}
	
	if (memcmp (actual->data, expected->data, actual->len) != 0) {
		testsuite_check_failed ("%s failed: stream contents do not match", what);
		goto error;
	}
	
	testsuite_check_passed ();
	
error:
	
	g_byte_array_free (expected, TRUE);
	g_byte_array_free (actual, TRUE);
}
Exemplo n.º 7
0
static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
{
	unsigned char status, BT_CAP[8];
	static enum bt_states last_printed = BT_STATE_PRINTME;
	int i;

	status = BT_STATUS;
	bt->nonzero_status |= status;
	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
			STATE2TXT,
			STATUS2TXT,
			bt->timeout,
			time);
		last_printed = bt->state;
	}

	/*
	 * Commands that time out may still (eventually) provide a response.
	 * This stale response will get in the way of a new response so remove
	 * it if possible (hopefully during IDLE).  Even if it comes up later
	 * it will be rejected by its (now-forgotten) seq number.
	 */

	if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
		drain_BMC2HOST(bt);
		BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
	}

	if ((bt->state != BT_STATE_IDLE) &&
	    (bt->state <  BT_STATE_PRINTME)) {
		/* check timeout */
		bt->timeout -= time;
		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
			return error_recovery(bt,
					      status,
					      IPMI_TIMEOUT_ERR);
	}

	switch (bt->state) {

	/*
	 * Idle state first checks for asynchronous messages from another
	 * channel, then does some opportunistic housekeeping.
	 */

	case BT_STATE_IDLE:
		if (status & BT_SMS_ATN) {
			BT_CONTROL(BT_SMS_ATN);	/* clear it */
			return SI_SM_ATTN;
		}

		if (status & BT_H_BUSY)		/* clear a leftover H_BUSY */
			BT_CONTROL(BT_H_BUSY);

		/* Read BT capabilities if it hasn't been done yet */
		if (!bt->BT_CAP_outreqs)
			BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
					SI_SM_CALL_WITHOUT_DELAY);
		bt->timeout = bt->BT_CAP_req2rsp;
		BT_SI_SM_RETURN(SI_SM_IDLE);

	case BT_STATE_XACTION_START:
		if (status & (BT_B_BUSY | BT_H2B_ATN))
			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
		if (BT_STATUS & BT_H_BUSY)
			BT_CONTROL(BT_H_BUSY);	/* force clear */
		BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
				SI_SM_CALL_WITHOUT_DELAY);

	case BT_STATE_WRITE_BYTES:
		if (status & BT_H_BUSY)
			BT_CONTROL(BT_H_BUSY);	/* clear */
		BT_CONTROL(BT_CLR_WR_PTR);
		write_all_bytes(bt);
		BT_CONTROL(BT_H2B_ATN);	/* can clear too fast to catch */
		BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
				SI_SM_CALL_WITHOUT_DELAY);

	case BT_STATE_WRITE_CONSUME:
		if (status & (BT_B_BUSY | BT_H2B_ATN))
			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
		BT_STATE_CHANGE(BT_STATE_READ_WAIT,
				SI_SM_CALL_WITHOUT_DELAY);

	/* Spinning hard can suppress B2H_ATN and force a timeout */

	case BT_STATE_READ_WAIT:
		if (!(status & BT_B2H_ATN))
			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
		BT_CONTROL(BT_H_BUSY);		/* set */

		/*
		 * Uncached, ordered writes should just proceeed serially but
		 * some BMCs don't clear B2H_ATN with one hit.  Fast-path a
		 * workaround without too much penalty to the general case.
		 */

		BT_CONTROL(BT_B2H_ATN);		/* clear it to ACK the BMC */
		BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
				SI_SM_CALL_WITHOUT_DELAY);

	case BT_STATE_CLEAR_B2H:
		if (status & BT_B2H_ATN) {
			/* keep hitting it */
			BT_CONTROL(BT_B2H_ATN);
			BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
		}
		BT_STATE_CHANGE(BT_STATE_READ_BYTES,
				SI_SM_CALL_WITHOUT_DELAY);

	case BT_STATE_READ_BYTES:
		if (!(status & BT_H_BUSY))
			/* check in case of retry */
			BT_CONTROL(BT_H_BUSY);
		BT_CONTROL(BT_CLR_RD_PTR);	/* start of BMC2HOST buffer */
		i = read_all_bytes(bt);		/* true == packet seq match */
		BT_CONTROL(BT_H_BUSY);		/* NOW clear */
		if (!i) 			/* Not my message */
			BT_STATE_CHANGE(BT_STATE_READ_WAIT,
					SI_SM_CALL_WITHOUT_DELAY);
		bt->state = bt->complete;
		return bt->state == BT_STATE_IDLE ?	/* where to next? */
			SI_SM_TRANSACTION_COMPLETE :	/* normal */
			SI_SM_CALL_WITHOUT_DELAY;	/* Startup magic */

	case BT_STATE_LONG_BUSY:	/* For example: after FW update */
		if (!(status & BT_B_BUSY)) {
			reset_flags(bt);	/* next state is now IDLE */
			bt_init_data(bt, bt->io);
		}
		return SI_SM_CALL_WITH_DELAY;	/* No repeat printing */

	case BT_STATE_RESET1:
		reset_flags(bt);
		drain_BMC2HOST(bt);
		BT_STATE_CHANGE(BT_STATE_RESET2,
				SI_SM_CALL_WITH_DELAY);

	case BT_STATE_RESET2:		/* Send a soft reset */
		BT_CONTROL(BT_CLR_WR_PTR);
		HOST2BMC(3);		/* number of bytes following */
		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
		HOST2BMC(42);		/* Sequence number */
		HOST2BMC(3);		/* Cmd == Soft reset */
		BT_CONTROL(BT_H2B_ATN);
		bt->timeout = BT_RESET_DELAY * 1000000;
		BT_STATE_CHANGE(BT_STATE_RESET3,
				SI_SM_CALL_WITH_DELAY);

	case BT_STATE_RESET3:		/* Hold off everything for a bit */
		if (bt->timeout > 0)
			return SI_SM_CALL_WITH_DELAY;
		drain_BMC2HOST(bt);
		BT_STATE_CHANGE(BT_STATE_RESTART,
				SI_SM_CALL_WITH_DELAY);

	case BT_STATE_RESTART:		/* don't reset retries or seq! */
		bt->read_count = 0;
		bt->nonzero_status = 0;
		bt->timeout = bt->BT_CAP_req2rsp;
		BT_STATE_CHANGE(BT_STATE_XACTION_START,
				SI_SM_CALL_WITH_DELAY);

	/*
	 * Get BT Capabilities, using timing of upper level state machine.
	 * Set outreqs to prevent infinite loop on timeout.
	 */
	case BT_STATE_CAPABILITIES_BEGIN:
		bt->BT_CAP_outreqs = 1;
		{
			unsigned char GetBT_CAP[] = { 0x18, 0x36 };
			bt->state = BT_STATE_IDLE;
			bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP));
		}
		bt->complete = BT_STATE_CAPABILITIES_END;
		BT_STATE_CHANGE(BT_STATE_XACTION_START,
				SI_SM_CALL_WITH_DELAY);

	case BT_STATE_CAPABILITIES_END:
		i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP));
		bt_init_data(bt, bt->io);
		if ((i == 8) && !BT_CAP[2]) {
			bt->BT_CAP_outreqs = BT_CAP[3];
			bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000;
			bt->BT_CAP_retries = BT_CAP[7];
		} else
			printk(KERN_WARNING "IPMI BT: using default values\n");
		if (!bt->BT_CAP_outreqs)
			bt->BT_CAP_outreqs = 1;
		printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n",
			bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries);
		bt->timeout = bt->BT_CAP_req2rsp;
		return SI_SM_CALL_WITHOUT_DELAY;

	default:	/* should never occur */
		return error_recovery(bt,
				      status,
				      IPMI_ERR_UNSPECIFIED);
	}
	return SI_SM_CALL_WITH_DELAY;
}
Exemplo n.º 8
0
static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
{
	unsigned char status;
	char buf[40]; /* For getting status */
	int i;

	status = BT_STATUS;
	bt->nonzero_status |= status;

	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))
		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
			STATE2TXT,
			STATUS2TXT(buf),
			bt->timeout,
			time);
	bt->last_state = bt->state;

	if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;

	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */

		/* Certain states, on error conditions, can lock up a CPU
		   because they are effectively in an infinite loop with
		   CALL_WITHOUT_DELAY (right back here with time == 0).
		   Prevent infinite lockup by ALWAYS decrementing timeout. */

    	/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
              (noticed in ipmi_smic_sm.c January 2004) */

		if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
		bt->timeout -= time;
		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
			error_recovery(bt, "timed out");
			return SI_SM_CALL_WITHOUT_DELAY;
		}
	}

	switch (bt->state) {

    	case BT_STATE_IDLE:	/* check for asynchronous messages */
		if (status & BT_SMS_ATN) {
			BT_CONTROL(BT_SMS_ATN);	/* clear it */
			return SI_SM_ATTN;
		}
		return SI_SM_IDLE;

	case BT_STATE_XACTION_START:
		if (status & BT_H_BUSY) {
			BT_CONTROL(BT_H_BUSY);
			break;
		}
    		if (status & BT_B2H_ATN) break;
		bt->state = BT_STATE_WRITE_BYTES;
		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */

	case BT_STATE_WRITE_BYTES:
		if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
		BT_CONTROL(BT_CLR_WR_PTR);
		write_all_bytes(bt);
		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */
		bt->state = BT_STATE_WRITE_CONSUME;
		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */

	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
        	if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
		bt->state = BT_STATE_B2H_WAIT;
		/* fall through with status */

	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning
	   hard here, constantly reading status, seems to hold off the
	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */

	case BT_STATE_B2H_WAIT:
    		if (!(status & BT_B2H_ATN)) break;

		/* Assume ordered, uncached writes: no need to wait */
		if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */
		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */
		i = read_all_bytes(bt);
		BT_CONTROL(BT_H_BUSY);		/* clear */
		if (!i) break;			/* Try this state again */
		bt->state = BT_STATE_READ_END;
		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */

    	case BT_STATE_READ_END:

		/* I could wait on BT_H_BUSY to go clear for a truly clean
		   exit.  However, this is already done in XACTION_START
		   and the (possible) extra loop/status/possible wait affects
		   performance.  So, as long as it works, just ignore H_BUSY */

#ifdef MAKE_THIS_TRUE_IF_NECESSARY

		if (status & BT_H_BUSY) break;
#endif
		bt->seq++;
		bt->state = BT_STATE_IDLE;
		return SI_SM_TRANSACTION_COMPLETE;

	case BT_STATE_RESET1:
    		reset_flags(bt);
    		bt->timeout = BT_RESET_DELAY;
		bt->state = BT_STATE_RESET2;
		break;

	case BT_STATE_RESET2:		/* Send a soft reset */
		BT_CONTROL(BT_CLR_WR_PTR);
		HOST2BMC(3);		/* number of bytes following */
		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
		HOST2BMC(42);		/* Sequence number */
		HOST2BMC(3);		/* Cmd == Soft reset */
		BT_CONTROL(BT_H2B_ATN);
		bt->state = BT_STATE_RESET3;
		break;

	case BT_STATE_RESET3:
		if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
		bt->state = BT_STATE_RESTART;	/* printk in debug modes */
		break;

	case BT_STATE_RESTART:		/* don't reset retries! */
		bt->write_data[2] = ++bt->seq;
		bt->read_count = 0;
		bt->nonzero_status = 0;
		bt->timeout = BT_NORMAL_TIMEOUT;
		bt->state = BT_STATE_XACTION_START;
		break;

	default:	/* HOSED is supposed to be caught much earlier */
		error_recovery(bt, "internal logic error");
		break;
  	}
  	return SI_SM_CALL_WITH_DELAY;
}
Exemplo n.º 9
0
static void
test_gunzip (const char *datadir, const char *filename)
{
	char *name = g_strdup_printf ("%s.gz", filename);
	char *path = g_build_filename (datadir, name, NULL);
	const char *what = "GMimeFilterGzip::unzip";
	GByteArray *actual, *expected;
	GMimeStream *stream;
	GMimeFilter *filter;
	const char *value;
	
	testsuite_check ("%s", what);
	
	actual = g_byte_array_new ();
	stream = g_mime_stream_mem_new_with_byte_array (actual);
	g_mime_stream_mem_set_owner ((GMimeStreamMem *) stream, FALSE);
	
	filter = g_mime_filter_gzip_new (GMIME_FILTER_GZIP_MODE_UNZIP, 9);
	
	pump_data_through_filter (filter, path, stream, FALSE, TRUE);
	g_object_unref (stream);
	g_free (path);
	g_free (name);
	
	path = g_build_filename (datadir, filename, NULL);
	expected = read_all_bytes (path, TRUE);
	g_free (path);
	
	if (actual->len != expected->len) {
		testsuite_check_failed ("%s failed: stream lengths do not match: expected=%u; actual=%u",
					what, expected->len, actual->len);
		goto error;
	}
	
	if (memcmp (actual->data, expected->data, actual->len) != 0) {
		testsuite_check_failed ("%s failed: stream contents do not match", what);
		goto error;
	}
	
	value = g_mime_filter_gzip_get_filename ((GMimeFilterGZip *) filter);
	if (!value || strcmp (value, filename) != 0) {
		testsuite_check_failed ("%s failed: filename does not match: %s", what, value);
		goto error;
	}
	
	value = g_mime_filter_gzip_get_comment ((GMimeFilterGZip *) filter);
	if (!value || strcmp (value, "This is a comment.") != 0) {
		testsuite_check_failed ("%s failed: comment does not match: %s", what, value);
		goto error;
	}
	
	testsuite_check_passed ();
	
error:
	
	g_byte_array_free (expected, TRUE);
	g_byte_array_free (actual, TRUE);
	
	g_mime_filter_reset (filter);
	g_object_unref (filter);
}