Unit tests for SmartRest

Dependencies:   C027 SmartRest mbed

Files at this revision

API Documentation at this revision

Comitter:
vwochnik
Date:
Mon Mar 24 10:12:45 2014 +0000
Commit message:
fix

Changed in this revision

C027.lib Show annotated file Show diff for this revision Revisions of this file
SmartRest.lib Show annotated file Show diff for this revision Revisions of this file
client/SmartRestTest.cpp Show annotated file Show diff for this revision Revisions of this file
client/SmartRestTest.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mock/BufferedDataSink.cpp Show annotated file Show diff for this revision Revisions of this file
mock/BufferedDataSink.h Show annotated file Show diff for this revision Revisions of this file
mock/BufferedDataSource.cpp Show annotated file Show diff for this revision Revisions of this file
mock/BufferedDataSource.h Show annotated file Show diff for this revision Revisions of this file
mock/MockClient.cpp Show annotated file Show diff for this revision Revisions of this file
mock/MockClient.h Show annotated file Show diff for this revision Revisions of this file
mock/MockSmartRest.cpp Show annotated file Show diff for this revision Revisions of this file
mock/MockSmartRest.h Show annotated file Show diff for this revision Revisions of this file
parser/ParserTest.cpp Show annotated file Show diff for this revision Revisions of this file
parser/ParserTest.h Show annotated file Show diff for this revision Revisions of this file
values/AggregatorTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/AggregatorTest.h Show annotated file Show diff for this revision Revisions of this file
values/CharValueTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/CharValueTest.h Show annotated file Show diff for this revision Revisions of this file
values/ComposedRecordTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/ComposedRecordTest.h Show annotated file Show diff for this revision Revisions of this file
values/FloatValueTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/FloatValueTest.h Show annotated file Show diff for this revision Revisions of this file
values/IntegerValueTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/IntegerValueTest.h Show annotated file Show diff for this revision Revisions of this file
values/ParsedValueTest.cpp Show annotated file Show diff for this revision Revisions of this file
values/ParsedValueTest.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027.lib	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/ublox/code/C027/#37252d7bcd9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SmartRest.lib	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/vwochnik/code/SmartRest/#744801d5734d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/SmartRestTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,43 @@
+#include "SmartRestTest.h"
+#include <string.h>
+#include <assert.h>
+#include <ComposedRecord.h>
+#include <CharValue.h>
+#include <IntegerValue.h>
+#include <ParsedRecord.h>
+
+SmartRestTest::SmartRestTest() : _smart("com_cumulocity_MockDevice")
+{
+}
+
+void SmartRestTest::test()
+{
+    // will receive an "echo ok" message later on.
+    _smart.client().receiveData("20,12345\r\n");
+
+    {
+        // prepare sending data generator
+        IntegerValue v1(10);CharValue v2("This is me!");
+        Value *varr[2] = {&v1, &v2};
+        ComposedRecord record;
+        record.add(v1).add(v2);
+
+        // send data
+        assert(_smart.send(record) == SMARTREST_SUCCESS);
+        // make sure it 'got there'
+        assert(strcmp("10,This is me!\r\n", _smart.client().sentData()) == 0);
+    }
+
+    {
+        ParsedRecord record;
+        assert(_smart.receive(record) == SMARTREST_SUCCESS);
+
+        assert(record);
+        assert(record.values() == 2);
+        assert(record.value(0).integerValue() == 20);
+        assert(record.value(1).integerValue() == 12345);
+
+        assert(_smart.receive(record) == SMARTREST_END_OF_RESPONSE);
+        assert(!record);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/SmartRestTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,18 @@
+#ifndef SMARTRESTTEST_H
+#define SMARTRESTTEST_H
+
+#include <stddef.h>
+#include "../mock/MockSmartRest.h"
+
+class SmartRestTest
+{
+public:
+    SmartRestTest();
+
+    void test();
+
+private:
+    MockSmartRest _smart;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,39 @@
+#include "mbed.h"
+#include "C027.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "SmartRestTest.h"
+#include "ParserTest.h"
+#include "CharValueTest.h"
+#include "FloatValueTest.h"
+#include "IntegerValueTest.h"
+#include "ParsedValueTest.h"
+#include "ComposedRecordTest.h"
+#include "AggregatorTest.h"
+
+int main() {
+    puts("Hello!");
+    puts("Testing client...");
+    SmartRestTest test1;
+    test1.test();
+    
+    puts("Testing parser...");
+    ParserTest test2;
+    test2.testAll();
+    
+    puts("Testing values...");
+    CharValueTest test3;
+    test3.test();
+    FloatValueTest test4;
+    test4.test();
+    IntegerValueTest test5;
+    test5.test();
+    ParsedValueTest test6;
+    test6.test();
+    ComposedRecordTest test7;
+    test7.test();
+    AggregatorTest test8;
+    test8.testAll();
+
+    puts("Everything is OK.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/BufferedDataSink.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,82 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "BufferedDataSink.h"
+
+BufferedDataSink::BufferedDataSink()
+{
+    _size = BDS_MEMORY_INCREMENT;
+    _buffer = (char*)malloc(_size*sizeof(char));
+    *_buffer = 0;
+    _ptr = _buffer;
+}
+
+BufferedDataSink::~BufferedDataSink()
+{
+    free(_buffer);
+}
+
+char * BufferedDataSink::value()
+{
+    return _buffer;
+}
+
+void BufferedDataSink::clear()
+{
+    _ptr = _buffer;
+    *_ptr = 0;
+}
+
+size_t BufferedDataSink::write(char c)
+{
+    ensureMinimumFreeMemory(1);
+    *_ptr++ = c;
+    *_ptr = 0;
+    return 1;
+}
+
+size_t BufferedDataSink::write(void *buf, size_t length)
+{
+    ensureMinimumFreeMemory(length);
+    memcpy(_ptr, buf, length);
+    _ptr += length;
+    *_ptr = 0;
+    return length;
+}
+
+size_t BufferedDataSink::write(const char *str)
+{
+    return write((void*)str, strlen(str)*sizeof(char));
+}
+
+size_t BufferedDataSink::write(unsigned long number)
+{
+    size_t length;
+
+    length = snprintf(NULL, 0, "%lu", number);
+
+    ensureMinimumFreeMemory(length);
+    length = sprintf(_ptr, "%lu", number);
+    _ptr += length;
+    return length;
+}
+
+void BufferedDataSink::ensureMinimumFreeMemory(size_t required)
+{
+    size_t size = _size, offset = _ptr - _buffer;
+
+    if (required < BDS_MIN_FREE_MEMORY)
+        required = BDS_MIN_FREE_MEMORY;
+    else
+        required++;
+
+    while (size - offset < required)
+        size += BDS_MEMORY_INCREMENT;
+
+    if (size == _size)
+        return;
+
+    _size = size;
+    _buffer = (char*)realloc(_buffer, _size*sizeof(char));
+    _ptr = _buffer + offset;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/BufferedDataSink.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,34 @@
+#ifndef BUFFEREDDATASINK_H
+#define BUFFEREDDATASINK_H
+
+#include <stddef.h>
+#include <AbstractDataSink.h>
+
+// the minimal free memory
+#define BDS_MIN_FREE_MEMORY 25
+// the initial memory and memory increment
+#define BDS_MEMORY_INCREMENT 128
+
+class BufferedDataSink : public AbstractDataSink
+{
+public:
+    BufferedDataSink();
+    ~BufferedDataSink();
+
+    char * value();
+    void clear();
+
+    size_t write(char c);
+    size_t write(void *buf, size_t length);
+    size_t write(const char *str);
+    size_t write(unsigned long number);
+
+protected:
+    void ensureMinimumFreeMemory(size_t required);
+
+private:
+    char *_buffer, *_ptr;
+    size_t _size;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/BufferedDataSource.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "BufferedDataSource.h"
+
+BufferedDataSource::BufferedDataSource()
+{
+    clear();
+}
+
+void BufferedDataSource::set(char *buf, size_t length)
+{
+    _data = _ptr = buf;
+    _length = length;
+}
+
+void BufferedDataSource::set(const char *str)
+{
+    _data = _ptr = (char *)str;
+    _length = strlen(str);
+}
+
+void BufferedDataSource::clear()
+{
+    _data = _ptr = NULL;
+    _length = 0;
+}
+
+bool BufferedDataSource::exhausted()
+{
+    return (_ptr - _data) == _length;
+}
+
+char BufferedDataSource::read()
+{
+    if (exhausted())
+        return 0;
+    return *_ptr++;
+}
+
+uint8_t BufferedDataSource::status()
+{
+    if (exhausted())
+        return DS_STATUS_CLOSED;
+    return DS_STATUS_OK;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/BufferedDataSource.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,25 @@
+#ifndef BUFFEREDDATASOURCE_H
+#define BUFFEREDDATASOURCE_H
+
+#include <stddef.h>
+#include <AbstractDataSource.h>
+
+class BufferedDataSource : public AbstractDataSource
+{
+public:
+    BufferedDataSource();
+
+    void set(char *buf, size_t length);
+    void set(const char *str);
+    void clear();
+
+    bool exhausted();
+    char read();
+    uint8_t status();
+
+private:
+    char *_data, *_ptr;
+    size_t _length;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/MockClient.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,91 @@
+#include "MockClient.h"
+
+#define STATE_INIT 0
+#define STATE_IN_REQUEST 1
+#define STATE_SENT_ID 2
+#define STATE_SENT_DATA 3
+#define STATE_REQ_COMPLETE 4
+#define STATE_RECVD_RESPONSE 5
+#define STATE_RECV_DATA 6
+
+MockClient::MockClient()
+{
+    _state = STATE_INIT;
+    _data = NULL;
+    _ident = NULL;
+}
+
+void MockClient::receiveData(const char* str)
+{
+    _data = str;
+}
+
+char* MockClient::sentData()
+{
+    return _sink.value();
+}
+
+void MockClient::clearSent()
+{
+    _sink.clear();
+}
+
+uint8_t MockClient::beginRequest()
+{
+    if (_state != STATE_INIT)
+        return CLIENT_INTERNAL_ERROR;
+    _state = STATE_IN_REQUEST;
+    return CLIENT_OK;
+}
+
+uint8_t MockClient::sendIdentifier(const char* identifier)
+{
+    if (_state != STATE_IN_REQUEST)
+        return CLIENT_INTERNAL_ERROR;
+    _ident = (char*)identifier;
+    _state = STATE_SENT_ID;
+    return CLIENT_OK;
+}
+
+uint8_t MockClient::sendData(DataGenerator& generator)
+{
+    if (_state != STATE_SENT_ID)
+        return CLIENT_INTERNAL_ERROR;
+    generator.writeTo(_sink);
+    _state = STATE_SENT_DATA;
+    return CLIENT_OK;
+}
+
+uint8_t MockClient::endRequest()
+{
+    if ((_state != STATE_SENT_ID) && (_state != STATE_SENT_DATA))
+        return CLIENT_INTERNAL_ERROR;
+    _state = STATE_REQ_COMPLETE;
+    return CLIENT_OK;
+}
+
+uint8_t MockClient::awaitResponse()
+{
+    if (_state != STATE_REQ_COMPLETE)
+        return CLIENT_INTERNAL_ERROR;
+    _state = STATE_RECVD_RESPONSE;
+    return CLIENT_OK;
+}
+
+AbstractDataSource& MockClient::receiveData()
+{
+    if ((_state == STATE_RECVD_RESPONSE) && (_data != NULL))
+        _source.set(_data);
+    else
+        _source.clear();
+    _state = STATE_RECV_DATA;
+    return _source;
+}
+
+void MockClient::stop()
+{
+    _state = STATE_INIT;
+    _sink.clear();
+    _source.clear();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/MockClient.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,38 @@
+#ifndef MOCKCLIENT_H
+#define MOCKCLIENT_H
+
+#include <stdint.h>
+#include <AbstractClient.h>
+#include "BufferedDataSource.h"
+#include "BufferedDataSink.h"
+
+#define CLIENT_OK 0
+#define CLIENT_CONNECTION_ERROR 1
+#define CLIENT_INTERNAL_ERROR 2
+
+class MockClient : public AbstractClient
+{
+public:
+    MockClient();
+
+    void receiveData(const char* str);
+    char* sentData();
+    void clearSent();
+    char* lastIdentifier();
+
+    uint8_t beginRequest();
+    uint8_t sendIdentifier(const char*);
+    uint8_t sendData(DataGenerator& generator);
+    uint8_t endRequest();
+    uint8_t awaitResponse();
+    AbstractDataSource& receiveData();
+    void stop();
+private:
+    uint8_t _state;
+    const char *_data;
+    const char *_ident;
+    BufferedDataSink _sink;
+    BufferedDataSource _source;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/MockSmartRest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,11 @@
+#include "MockSmartRest.h"
+
+MockSmartRest::MockSmartRest(const char *identifier) : SmartRest(_client, identifier)
+{
+}
+
+MockClient& MockSmartRest::client()
+{
+    return _client;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mock/MockSmartRest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,16 @@
+#ifndef MOCKSMARTREST_H
+#define MOCKSMARTREST_H
+
+#include <SmartRest.h>
+#include "MockClient.h"
+
+class MockSmartRest : public SmartRest
+{
+public:
+    MockSmartRest(const char*);
+    MockClient& client();
+private:
+    MockClient _client;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser/ParserTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,79 @@
+#include "ParserTest.h"
+#include <stdio.h>
+#include <assert.h>
+#include <ParsedRecord.h>
+#include <string.h>
+
+ParserTest::ParserTest()
+{
+}
+
+void ParserTest::testAll()
+{
+    puts("Parser test scenario 1");
+    testScenario1();
+    puts("Parser test scenario 2");
+    testScenario2();
+    puts("Parser test scenario 3");
+    testScenario3();
+}
+
+void ParserTest::testScenario1()
+{
+    ParsedRecord record; uint8_t res;
+    char str[] = "100,Value1,Value2\r\n";
+
+    _source.set(str);
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_SUCCESS);
+    assert(record);
+    assert(record.values() == 3);
+    assert(record.value(0).integerValue() == 100);
+    assert(strcmp(record.value(1).characterValue(), "Value1") == 0);
+    assert(strcmp(record.value(2).characterValue(), "Value2") == 0);
+
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_END_OF_RESPONSE);
+    assert(!record);
+}
+
+void ParserTest::testScenario2()
+{
+    ParsedRecord record; uint8_t res;
+    char str[] = "100,Value1,Value2\r\n"
+                 "200,\"Hello, Test\", hello ,5.3\r\n";
+
+    _source.set(str);
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_SUCCESS);
+    assert(record);
+    assert(record.values() == 3);
+    assert(record.value(0).integerValue() == 100);
+    assert(strcmp(record.value(1).characterValue(), "Value1") == 0);
+    assert(strcmp(record.value(2).characterValue(), "Value2") == 0);
+
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_SUCCESS);
+    assert(record);
+    assert(record.values() == 4);
+    assert(record.value(0).integerValue() == 200);
+    assert(strcmp(record.value(1).characterValue(), "Hello, Test") == 0);
+    assert(strcmp(record.value(2).characterValue(), "hello") == 0);
+    assert(record.value(3).floatValue() == 5.3);
+
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_END_OF_RESPONSE);
+    assert(!record);
+}
+
+void ParserTest::testScenario3()
+{
+    ParsedRecord record; uint8_t res;
+    char str[] = "100,Val\"\"ue1,Value2\r\n";
+
+    _source.set(str);
+    res = _parser.readFrom(_source, record);
+    assert(res == PARSER_PARSE_ERROR);
+    assert(!record);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser/ParserTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,25 @@
+#ifndef PARSERTEST_H
+#define PARSERTEST_H
+
+#include <stdint.h>
+#include "../mock/BufferedDataSource.h"
+#include <Parser.h>
+
+class ParserTest
+{
+public:
+    ParserTest();
+
+    void testAll();
+
+protected:
+    void testScenario1();
+    void testScenario2();
+    void testScenario3();
+
+private:
+    BufferedDataSource _source;
+    Parser _parser;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/AggregatorTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,80 @@
+#include "AggregatorTest.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <StaticData.h>
+#include <CharValue.h>
+#include <IntegerValue.h>
+#include <FloatValue.h>
+#include <ComposedRecord.h>
+
+AggregatorTest::AggregatorTest()
+{
+}
+
+void AggregatorTest::testAll()
+{
+    test1();
+    test2();
+}
+
+void AggregatorTest::test1()
+{
+    assert((_aggr.length() + _aggr.writtenLength()) == 0);
+
+    DataGenerator *copy = NULL;
+    for (size_t a = 1; a < 11; a++) {
+        printf("Filling aggregator for the %dth time\n", a);
+
+        StaticData data("This is a test.", true);
+        assert(data.writtenLength() == 15);
+
+        for (size_t n = 0; n < a*10; n++) {
+            assert(_aggr.add(data));
+            assert(_aggr.length() == n+1);
+            if (n % 10 == 0) {
+                assert(_aggr.writtenLength() == (n+1)*data.writtenLength());
+            }
+        }
+        if (copy != NULL)
+            delete copy;
+        copy = _aggr.copy();
+        assert(_aggr.writtenLength() == copy->writtenLength());
+        _aggr.clear();
+    }
+
+    assert((_aggr.length() + _aggr.writtenLength()) == 0);
+
+    assert(copy->writtenLength() == 1000*10*15);
+    delete copy;
+}
+
+void AggregatorTest::test2()
+{
+    assert((_aggr.length() + _aggr.writtenLength()) == 0);
+
+    for (size_t a = 1; a < 11; a++) {
+        printf("Filling aggregator for the %dth time\n", a);
+
+        for (size_t n = 0; n < a*10; n++) {
+            CharValue v1("Test...");
+            FloatValue v2(3.1459*n, 4);
+            IntegerValue v3(300*n);
+            ComposedRecord data;
+            data.add(v1).add(v2).add(v3);
+
+            _aggr.add(data);
+            if (n % 10 == 0) {
+                assert(_aggr.writtenLength() == (n+1)*data.writtenLength());
+            }
+        }
+
+        size_t len = _aggr.writtenLength();
+        DataGenerator *copy = _aggr.copy();
+        assert(_aggr.writtenLength() == copy->writtenLength());
+        _aggr.clear();
+        assert(copy->writtenLength() == len);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/AggregatorTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,19 @@
+#ifndef AGGREGATORTEST_H
+#define AGGREGATORTEST_H
+
+#include <stddef.h>
+#include <Aggregator.h>
+
+class AggregatorTest
+{
+public:
+    AggregatorTest();
+    void testAll();
+    void test1();
+    void test2();
+
+private:
+    Aggregator _aggr;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/CharValueTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,62 @@
+#include "CharValueTest.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+CharValueTest::CharValueTest()
+{
+}
+
+void CharValueTest::test()
+{
+    testValue("abc", "abc");
+    testValue("hello world", "hello world");
+    testValue("hello, world", "\"hello, world\"");
+    testValue(" hello world", "\" hello world\"");
+    testValue("hello world ", "\"hello world \"");
+    testValue("hello\"world", "\"hello\"\"world\"");
+    testValue("hello\"\"world", "\"hello\"\"\"\"world\"");
+    testValue("hello\",world ", "\"hello\"\",world \"");
+    testNull();
+}
+
+void CharValueTest::testValue(const char *string, const char *expected)
+{
+    printf("Expecting '%s' for value '%s'\n", expected, string);
+    CharValue value(string);
+    assert(value.length() == strlen(expected));
+    assert(value.valueType() == VALUE_CHARACTER);
+    assert(value.characterValue() == string);
+    value.write(sink);
+    assert(strcmp(expected, sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(strcmp(copy->characterValue(), value.characterValue()) == 0);
+    assert(copy->characterValue() != value.characterValue());
+    delete copy;
+}
+
+void CharValueTest::testNull()
+{
+    puts("Testing character null value.");
+
+    CharValue value("");
+    assert(value.length() == 0);
+    assert(value.valueType() == VALUE_NULL);
+    assert(value.characterValue() == NULL);
+    value.write(sink);
+    assert(strcmp("", sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(copy->characterValue() == value.characterValue());
+    delete copy;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/CharValueTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,23 @@
+#ifndef CHARVALUETEST_H
+#define CHARVALUETEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "CharValue.h"
+#include "../mock/BufferedDataSink.h"
+
+class CharValueTest
+{
+public:
+    CharValueTest();
+
+    void test();
+protected:
+    void testValue(const char *string, const char *expected);
+    void testNull();
+
+private:
+    BufferedDataSink sink;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/ComposedRecordTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,43 @@
+#include "ComposedRecordTest.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+#include "FloatValue.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+ComposedRecordTest::ComposedRecordTest()
+{
+}
+
+void ComposedRecordTest::test()
+{
+    CharValue hello("Hello World!");
+    CharValue random("RandomValue");
+    CharValue test(" \", ");
+    IntegerValue someNumber(12345);
+    FloatValue pi(3.141, 2);
+
+    Value *v1[2] = {&hello, &pi};
+    testValue(v1, 2, "Hello World!,3.14\r\n");
+
+    Value *v2[3] = {&someNumber, &random, &pi};
+    testValue(v2, 3, "12345,RandomValue,3.14\r\n");
+
+    Value *v3[2] = {&random,&test};
+    testValue(v3, 2, "RandomValue,\" \"\", \"\r\n");
+}
+
+void ComposedRecordTest::testValue(Value **values, size_t count, const char *expected)
+{
+    printf("Now testing a composed record with %lu values. Expected value: %s", count, expected);
+    ComposedRecord record;
+    for (size_t n = 0; n < count; n++)
+        record.add(*values[n]);
+
+    assert(record.writtenLength() == strlen(expected));
+    record.writeTo(sink);
+    assert(strcmp(expected, sink.value()) == 0);
+    sink.clear();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/ComposedRecordTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,22 @@
+#ifndef COMPOSEDRECORDTEST_H
+#define COMPOSEDRECORDTEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "ComposedRecord.h"
+#include "Value.h"
+#include "../mock/BufferedDataSink.h"
+
+class ComposedRecordTest
+{
+public:
+    ComposedRecordTest();
+
+    void test();
+    void testValue(Value **values, size_t count, const char *expected);
+
+private:
+    BufferedDataSink sink;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/FloatValueTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,39 @@
+#include "FloatValueTest.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+FloatValueTest::FloatValueTest()
+{
+}
+
+void FloatValueTest::test()
+{
+    testValue(3, 0, "3");
+    testValue(3, 1, "3.0");
+    testValue(3, 5, "3.00000");
+    testValue(3.123456789, 0, "3");
+    testValue(3.123456789, 1, "3.1");
+    testValue(3.123456789, 5, "3.12346");
+    testValue(3.513456789, 1, "3.5");
+    testValue(3.593456789, 1, "3.6");
+}
+
+void FloatValueTest::testValue(double number, uint8_t digits, const char *expected)
+{
+    printf("Expecting output '%s' for number %f with precision %d\n", expected, number, digits);
+    FloatValue value(number, digits);
+    assert(value.length() == strlen(expected));
+    assert(value.valueType() == VALUE_FLOAT);
+    assert(value.floatValue() == number);
+    value.write(sink);
+    assert(strcmp(expected, sink.value()) == 0);
+    sink.clear();
+
+    Value* copy = value.copy();
+    assert(copy->floatValue() == value.floatValue());
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    delete copy;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/FloatValueTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,22 @@
+#ifndef FLOATVALUETEST_H
+#define FLOATVALUETEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "FloatValue.h"
+#include "../mock/BufferedDataSink.h"
+
+class FloatValueTest
+{
+public:
+    FloatValueTest();
+
+    void test();
+protected:
+    void testValue(double number, uint8_t digits, const char *expected);
+
+private:
+    BufferedDataSink sink;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/IntegerValueTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,37 @@
+#include "IntegerValueTest.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+IntegerValueTest::IntegerValueTest()
+{
+}
+
+void IntegerValueTest::test()
+{
+    testValue(0, "0");
+    testValue(-1, "-1");
+    testValue(400, "400");
+    testValue(-123456, "-123456");
+    testValue(123456, "123456");
+    testValue(123123123, "123123123");
+}
+
+void IntegerValueTest::testValue(long number, const char *expected)
+{
+    printf("Expecting '%s' for number %d\n", expected, number);
+    IntegerValue value(number);
+    assert(value.length() == strlen(expected));
+    assert(value.valueType() == VALUE_INTEGER);
+    assert(value.integerValue() == number);
+    value.write(sink);
+    assert(strcmp(expected, sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+    assert(copy->length() == value.length());
+    assert(copy->integerValue() == value.integerValue());
+    assert(copy->valueType() == value.valueType());
+    delete copy;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/IntegerValueTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,22 @@
+#ifndef INTEGERVALUETEST_H
+#define INTEGERVALUETEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "IntegerValue.h"
+#include "../mock/BufferedDataSink.h"
+
+class IntegerValueTest
+{
+public:
+    IntegerValueTest();
+
+    void test();
+protected:
+    void testValue(long number, const char *expected);
+
+private:
+    BufferedDataSink sink;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/ParsedValueTest.cpp	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,113 @@
+#include "ParsedValueTest.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+ParsedValueTest::ParsedValueTest()
+{
+}
+
+void ParsedValueTest::test()
+{
+    testNull();
+    testInteger("0", 0l);
+    testInteger("-1", -1l);
+    testInteger("1", 1l);
+    testInteger("300", 300l);
+    testInteger("-300", -300l);
+    testInteger("30000000000", 30000000000l);
+    testInteger("-30000000000", -30000000000l);
+    testFloat("1.0", 1.0);
+    testFloat(".1", 0.1);
+    testFloat("-.1", -0.1);
+    testFloat("-1.0", -1.0);
+    testFloat("1.2345", 1.2345);
+    testFloat("-1.2345", -1.2345);
+    testFloat("12345.2345", 12345.2345);
+    testFloat("-12345.2345", -12345.2345);
+    testCharacter("Hello", "Hello");
+    testCharacter("123123.", "123123.");
+    testCharacter("-123123.", "-123123.");
+    testCharacter("-", "-");
+}
+
+void ParsedValueTest::testNull()
+{
+    ParsedValue value("");
+    assert(value.valueType() == VALUE_NULL);
+    assert(value.characterValue() == NULL);
+    assert(value.integerValue() == 0l);
+    assert(value.floatValue() == 0.0);
+    assert(value.length() == 0);
+    value.write(sink);
+    assert(strcmp(sink.value(), "") == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(copy->characterValue() == value.characterValue());
+    delete copy;
+}
+
+void ParsedValueTest::testInteger(const char *string, long expected)
+{
+    ParsedValue value(string);
+    assert(value.length() == strlen(string));
+    assert(value.valueType() == VALUE_INTEGER);
+    assert(value.integerValue() == expected);
+    value.write(sink);
+    assert(strcmp(string, sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(copy->integerValue() == value.integerValue());
+    copy->write(sink);
+    assert(strcmp(string, sink.value()) == 0);
+    sink.clear();
+    delete copy;
+}
+
+void ParsedValueTest::testFloat(const char *string, double expected)
+{
+    ParsedValue value(string);
+    assert(value.length() == strlen(string));
+    assert(value.valueType() == VALUE_FLOAT);
+    assert(value.floatValue() == expected);
+    value.write(sink);
+    assert(strcmp(string, sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(copy->floatValue() == value.floatValue());
+    copy->write(sink);
+    assert(strcmp(string, sink.value()) == 0);
+    sink.clear();
+    delete copy;
+}
+
+void ParsedValueTest::testCharacter(const char *string, const char *expected)
+{
+    ParsedValue value(string);
+    assert(value.length() == strlen(expected));
+    assert(value.valueType() == VALUE_CHARACTER);
+    assert(value.characterValue() == string);
+    value.write(sink);
+    assert(strcmp(expected, sink.value()) == 0);
+    sink.clear();
+
+    Value *copy = value.copy();
+
+    assert(copy->length() == value.length());
+    assert(copy->valueType() == value.valueType());
+    assert(strcmp(copy->characterValue(), value.characterValue()) == 0);
+    assert(copy->characterValue() != value.characterValue());
+    delete copy;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/values/ParsedValueTest.h	Mon Mar 24 10:12:45 2014 +0000
@@ -0,0 +1,26 @@
+#ifndef PARSEDVALUETEST_H
+#define PARSEDVALUETEST_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "ParsedValue.h"
+#include "../mock/BufferedDataSink.h"
+
+class ParsedValueTest
+{
+public:
+    ParsedValueTest();
+
+    void test();
+
+protected:
+    void testNull();
+    void testInteger(const char *string, long expected);
+    void testFloat(const char *string, double expected);
+    void testCharacter(const char *string, const char *expected);
+
+private:
+    BufferedDataSink sink;
+};
+
+#endif