Index: uspace/lib/gfxfont/src/font.c
===================================================================
--- uspace/lib/gfxfont/src/font.c	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/gfxfont/src/font.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -375,5 +375,5 @@
 		return rc;
 
-	rc = riff_wchunk_write(riffw, (void *) props, sizeof(*props));
+	rc = riff_write(riffw, (void *) props, sizeof(*props));
 	if (rc != EOK)
 		return rc;
@@ -402,5 +402,5 @@
 		return rc;
 
-	rc = riff_wchunk_write(riffw, (void *) metrics, sizeof(*metrics));
+	rc = riff_write(riffw, (void *) metrics, sizeof(*metrics));
 	if (rc != EOK)
 		return rc;
@@ -445,5 +445,5 @@
 		return rc;
 
-	rc = riff_wchunk_write(riffw, (void *) alloc.pixels,
+	rc = riff_write(riffw, (void *) alloc.pixels,
 	    font->rect.p1.x * font->rect.p1.y * sizeof(uint32_t));
 	if (rc != EOK)
Index: uspace/lib/gfxfont/src/glyph.c
===================================================================
--- uspace/lib/gfxfont/src/glyph.c	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/gfxfont/src/glyph.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -331,5 +331,5 @@
 		return rc;
 
-	rc = riff_wchunk_write(riffw, (void *) metrics, sizeof(*metrics));
+	rc = riff_write(riffw, (void *) metrics, sizeof(*metrics));
 	if (rc != EOK)
 		return rc;
@@ -363,5 +363,5 @@
 		str = gfx_glyph_pattern_str(pat);
 
-		rc = riff_wchunk_write(riffw, (void *) str, 1 + str_size(str));
+		rc = riff_write(riffw, (void *) str, 1 + str_size(str));
 		if (rc != EOK)
 			return rc;
@@ -393,11 +393,9 @@
 		return rc;
 
-	rc = riff_wchunk_write(riffw, (void *) &glyph->rect,
-	    sizeof(glyph->rect));
-	if (rc != EOK)
-		return rc;
-
-	rc = riff_wchunk_write(riffw, (void *) &glyph->origin,
-	    sizeof(glyph->origin));
+	rc = riff_write(riffw, (void *) &glyph->rect, sizeof(glyph->rect));
+	if (rc != EOK)
+		return rc;
+
+	rc = riff_write(riffw, (void *) &glyph->origin, sizeof(glyph->origin));
 	if (rc != EOK)
 		return rc;
Index: uspace/lib/riff/doc/doxygroups.h
===================================================================
--- uspace/lib/riff/doc/doxygroups.h	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
+++ uspace/lib/riff/doc/doxygroups.h	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -0,0 +1,3 @@
+/** @addtogroup libriff libriff
+ * @ingroup libs
+ */
Index: uspace/lib/riff/include/riff/chunk.h
===================================================================
--- uspace/lib/riff/include/riff/chunk.h	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/riff/include/riff/chunk.h	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -45,5 +45,5 @@
 extern errno_t riff_wchunk_start(riffw_t *, riff_ckid_t, riff_wchunk_t *);
 extern errno_t riff_wchunk_end(riffw_t *, riff_wchunk_t *);
-extern errno_t riff_wchunk_write(riffw_t *, void *, size_t);
+extern errno_t riff_write(riffw_t *, void *, size_t);
 extern errno_t riff_write_uint32(riffw_t *, uint32_t);
 
@@ -54,4 +54,5 @@
 extern errno_t riff_rchunk_end(riff_rchunk_t *);
 extern errno_t riff_read(riff_rchunk_t *, void *, size_t, size_t *);
+extern uint32_t riff_rchunk_size(riff_rchunk_t *);
 
 #endif
Index: uspace/lib/riff/meson.build
===================================================================
--- uspace/lib/riff/meson.build	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/riff/meson.build	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -31,2 +31,8 @@
 	'src/rwave.c',
 )
+
+test_src = files(
+	'test/chunk.c',
+	'test/main.c',
+	'test/rwave.c',
+)
Index: uspace/lib/riff/src/chunk.c
===================================================================
--- uspace/lib/riff/src/chunk.c	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/riff/src/chunk.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -152,4 +152,6 @@
 
 	cksize = pos - wchunk->ckstart;
+	if (pos % 2 != 0)
+		++pos;
 
 	if (fseek(rw->f, wchunk->ckstart - 4, SEEK_SET) < 0)
@@ -176,5 +178,5 @@
  * @return EOK on success, EIO on error.
  */
-errno_t riff_wchunk_write(riffw_t *rw, void *data, size_t bytes)
+errno_t riff_write(riffw_t *rw, void *data, size_t bytes)
 {
 	size_t nw;
@@ -281,4 +283,7 @@
 		return rc;
 
+	if (nread != sizeof(vle))
+		return ELIMIT;
+
 	*v = uint32_t_le2host(vle);
 	return EOK;
@@ -315,4 +320,14 @@
 error:
 	return rc;
+}
+
+/** Return chunk data size.
+ *
+ * @param rchunk RIFF chunk
+ * @return Pure data size (excluding type+size header) in bytes
+ */
+uint32_t riff_rchunk_size(riff_rchunk_t *rchunk)
+{
+	return rchunk->cksize;
 }
 
Index: uspace/lib/riff/src/rwave.c
===================================================================
--- uspace/lib/riff/src/rwave.c	(revision 003c4139d7ad847545f542bf5da3be65eb920764)
+++ uspace/lib/riff/src/rwave.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -137,5 +137,5 @@
 		goto error;
 
-	rc = riff_wchunk_write(ww->rw, &rwfmt, sizeof(rwfmt));
+	rc = riff_write(ww->rw, &rwfmt, sizeof(rwfmt));
 	if (rc != EOK)
 		goto error;
@@ -196,5 +196,5 @@
 		}
 
-		rc = riff_wchunk_write(ww->rw, ww->buf, now);
+		rc = riff_write(ww->rw, ww->buf, now);
 		if (rc != EOK) {
 			assert(rc == EIO);
Index: uspace/lib/riff/test/chunk.c
===================================================================
--- uspace/lib/riff/test/chunk.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
+++ uspace/lib/riff/test/chunk.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+#include <riff/chunk.h>
+#include <str.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(chunk);
+
+enum {
+	CKID_dat1 = 0x31746164,
+	CKID_dat2 = 0x32746164,
+	LTYPE_lst1 = 0x3174736C,
+	LTYPE_lst2 = 0x3274736C
+};
+
+/** Write and read back RIFF file containing just empty RIFF chunk */
+PCUT_TEST(empty)
+{
+	char fname[L_tmpnam];
+	char *p;
+	riffw_t *rw;
+	riffr_t *rr;
+	riff_wchunk_t wriffck;
+	riff_rchunk_t rriffck;
+	errno_t rc;
+
+	p = tmpnam(fname);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Write RIFF file */
+
+	rc = riff_wopen(p, &rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rw);
+
+	rc = riff_wchunk_start(rw, CKID_RIFF, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wclose(rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read back RIFF file */
+
+	rc = riff_ropen(p, &rriffck, &rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rr);
+
+	PCUT_ASSERT_INT_EQUALS(CKID_RIFF, rriffck.ckid);
+	PCUT_ASSERT_INT_EQUALS(0, riff_rchunk_size(&rriffck));
+
+	rc = riff_rclose(rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	(void) remove(p);
+}
+
+/** Write and read back RIFF file containing two data chunks */
+PCUT_TEST(data_chunks)
+{
+	char fname[L_tmpnam];
+	char *p;
+	char str1[] = "Hello";
+	char str2[] = "World!";
+	char buf[10];
+	size_t nread;
+	riffw_t *rw;
+	riffr_t *rr;
+	riff_wchunk_t wriffck;
+	riff_wchunk_t wdatack;
+	riff_rchunk_t rriffck;
+	riff_rchunk_t rdatack;
+	errno_t rc;
+
+	p = tmpnam(fname);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Write RIFF file */
+
+	rc = riff_wopen(p, &rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rw);
+
+	rc = riff_wchunk_start(rw, CKID_RIFF, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Write first data chunk */
+
+	rc = riff_wchunk_start(rw, CKID_dat1, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_write(rw, str1, str_size(str1));
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Write second data chunk */
+
+	rc = riff_wchunk_start(rw, CKID_dat2, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_write(rw, str2, str_size(str2));
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wclose(rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read back RIFF file */
+
+	rc = riff_ropen(p, &rriffck, &rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rr);
+
+	PCUT_ASSERT_INT_EQUALS(CKID_RIFF, rriffck.ckid);
+
+	/* Read first data chunk */
+
+	rc = riff_rchunk_start(&rriffck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_dat1, rdatack.ckid);
+
+	rc = riff_read(&rdatack, buf, sizeof(buf), &nread);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(str_size(str1), nread);
+	PCUT_ASSERT_INT_EQUALS(0, memcmp(buf, str1, nread));
+
+	rc = riff_rchunk_end(&rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read second data chunk */
+
+	rc = riff_rchunk_start(&rriffck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_dat2, rdatack.ckid);
+
+	rc = riff_read(&rdatack, buf, sizeof(buf), &nread);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(str_size(str2), nread);
+	PCUT_ASSERT_INT_EQUALS(0, memcmp(buf, str2, nread));
+
+	rc = riff_rchunk_end(&rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_rclose(rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	(void) remove(p);
+}
+
+/** Write and read back RIFF file containing two list chunks */
+PCUT_TEST(list_chunks)
+{
+	char fname[L_tmpnam];
+	char *p;
+	riffw_t *rw;
+	riffr_t *rr;
+	riff_wchunk_t wriffck;
+	riff_wchunk_t wlistck;
+	riff_wchunk_t wdatack;
+	riff_rchunk_t rriffck;
+	riff_rchunk_t rlistck;
+	riff_rchunk_t rdatack;
+	uint32_t ltype;
+	errno_t rc;
+
+	p = tmpnam(fname);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Write RIFF file */
+
+	rc = riff_wopen(p, &rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rw);
+
+	rc = riff_wchunk_start(rw, CKID_RIFF, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Write first list chunk with two data chunks */
+
+	rc = riff_wchunk_start(rw, CKID_LIST, &wlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_write_uint32(rw, LTYPE_lst1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_start(rw, CKID_dat1, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_start(rw, CKID_dat2, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Write second list chunk with one data chunk */
+
+	rc = riff_wchunk_start(rw, CKID_LIST, &wlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_write_uint32(rw, LTYPE_lst2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_start(rw, CKID_dat1, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wchunk_end(rw, &wriffck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_wclose(rw);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read back RIFF file */
+
+	rc = riff_ropen(p, &rriffck, &rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(rr);
+
+	PCUT_ASSERT_INT_EQUALS(CKID_RIFF, rriffck.ckid);
+
+	/* Read first list chunk with two data chunks */
+
+	rc = riff_rchunk_start(&rriffck, &rlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_LIST, rlistck.ckid);
+
+	rc = riff_read_uint32(&rlistck, &ltype);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(LTYPE_lst1, ltype);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_dat1, rdatack.ckid);
+
+	rc = riff_rchunk_end(&rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_dat2, rdatack.ckid);
+
+	rc = riff_rchunk_end(&rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(ELIMIT, rc);
+
+	rc = riff_rchunk_end(&rlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read second list chunk with one data chunk */
+
+	rc = riff_rchunk_start(&rriffck, &rlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_LIST, rlistck.ckid);
+
+	rc = riff_read_uint32(&rlistck, &ltype);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(LTYPE_lst2, ltype);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(CKID_dat1, rdatack.ckid);
+
+	rc = riff_rchunk_end(&rdatack);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(ELIMIT, rc);
+
+	rc = riff_rchunk_start(&rlistck, &rdatack);
+	PCUT_ASSERT_ERRNO_VAL(ELIMIT, rc);
+
+	rc = riff_rchunk_end(&rlistck);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = riff_rclose(rr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+//	(void) remove(p);
+}
+
+PCUT_EXPORT(chunk);
Index: uspace/lib/riff/test/main.c
===================================================================
--- uspace/lib/riff/test/main.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
+++ uspace/lib/riff/test/main.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+PCUT_INIT;
+
+PCUT_IMPORT(chunk);
+PCUT_IMPORT(rwave);
+
+PCUT_MAIN();
Index: uspace/lib/riff/test/rwave.c
===================================================================
--- uspace/lib/riff/test/rwave.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
+++ uspace/lib/riff/test/rwave.c	(revision d145ecbb23dd631ab7c9bcf5f13b55867dd2dac9)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <mem.h>
+#include <pcut/pcut.h>
+#include <riff/rwave.h>
+#include <stdio.h>
+#include <stdint.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(rwave);
+
+/** Write a WAVE file and read it back */
+PCUT_TEST(write_read)
+{
+	char fname[L_tmpnam];
+	char *p;
+	uint16_t samples[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+	uint16_t rsamples[10];
+	size_t nread;
+	rwavew_t *ww = NULL;
+	rwaver_t *wr = NULL;
+	rwave_params_t params;
+	rwave_params_t rparams;
+	errno_t rc;
+
+	p = tmpnam(fname);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Write RIFF wAVE file */
+
+	params.channels = 2;
+	params.bits_smp = 16;
+	params.smp_freq = 44100;
+
+	rc = rwave_wopen(p, &params, &ww);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(ww);
+
+	rc = rwave_write_samples(ww, (void *) samples, sizeof(samples));
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = rwave_wclose(ww);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Read back RIFF WAVE file */
+
+	rc = rwave_ropen(p, &rparams, &wr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(wr);
+
+	PCUT_ASSERT_INT_EQUALS(params.channels, rparams.channels);
+	PCUT_ASSERT_INT_EQUALS(params.bits_smp, rparams.bits_smp);
+	PCUT_ASSERT_INT_EQUALS(params.smp_freq, rparams.smp_freq);
+
+	rc = rwave_read_samples(wr, rsamples, sizeof(rsamples), &nread);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_INT_EQUALS(sizeof(samples), nread);
+
+	PCUT_ASSERT_INT_EQUALS(0, memcmp(samples, rsamples, sizeof(samples)));
+
+	rc = rwave_rclose(wr);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	(void) remove(p);
+}
+
+PCUT_EXPORT(rwave);
