From 469abde11faed216fae1c12e8e848db3be0c30bc Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@control.lth.se>
Date: Mon, 13 May 2013 19:50:39 +0200
Subject: [PATCH] Adedd a test suite that currently seems to work with Python,
 C and C#

---
 .bzrignore                   |   2 +
 Makefile                     |  15 ++
 test/Makefile                |  79 ++++++++++
 test/basic.lc                |   9 ++
 test/ccode.py                |  22 ---
 test/cscode.py               |  94 ------------
 test/relay_gen_c.py          |  67 ++++++++
 test/relay_gen_cs.py         | 121 +++++++++++++++
 test/run                     | 185 ----------------------
 test/run.py                  | 160 -------------------
 test/test_encoder_decoder.py | 290 +++++++++++++++++++++++++++++++++++
 test/test_simple.c           |  19 ---
 12 files changed, 583 insertions(+), 480 deletions(-)
 create mode 100644 Makefile
 create mode 100644 test/Makefile
 create mode 100644 test/basic.lc
 delete mode 100644 test/ccode.py
 delete mode 100755 test/cscode.py
 create mode 100755 test/relay_gen_c.py
 create mode 100755 test/relay_gen_cs.py
 delete mode 100755 test/run
 delete mode 100755 test/run.py
 create mode 100755 test/test_encoder_decoder.py
 delete mode 100644 test/test_simple.c

diff --git a/.bzrignore b/.bzrignore
index 791ee8e..97cb9f0 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -18,3 +18,5 @@ lib/java/se/lth/control/labcomm/LabCommSample.class
 lib/java/se/lth/control/labcomm/LabCommType.class
 lib/java/se/lth/control/labcomm/LabCommWriter.class
 gen
+labcomm.dll
+labcomm.jar
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8b55332
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+export LABCOMM_JAR=$(shell pwd)/compiler/labComm.jar
+export LABCOMM=java -jar $(LABCOMM_JAR) 
+
+all: compiler
+	$(MAKE) -C lib 
+	$(MAKE) -C lib/c run-test
+
+.PHONY: compiler
+compiler:
+	cd compiler ; ant jar
+
+
+.PHONY: test
+test:
+	$(MAKE) -C test -e
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..f9882e9
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,79 @@
+TESTS=basic simple
+LABCOMM_JAR=../compiler/labComm.jar
+LABCOMM=java -jar $(LABCOMM_JAR) 
+
+all:	$(TESTS:%=test_%)
+#	PYTHONPATH=../lib/python \
+#		./test_encoder_decoder.py --labcomm="$(LABCOMM)" basic.lc
+
+.PHONY: clean
+clean:
+	rm -rf gen
+
+.PHONY: test_%
+test_%: gen/%/c_relay \
+	gen/%/cs_code.cs \
+	gen/%/cs_relay.exe \
+	gen/%/signatures.py \
+	gen/%/java_code 
+	PYTHONPATH=../lib/python ./test_encoder_decoder.py \
+		--signatures=gen/$*/signatures.py \
+		--test /bin/tee gen/$*/testdata \
+		--test gen/$*/c_relay /dev/stdin /dev/stdout \
+		--test mono gen/$*/cs_relay.exe /dev/stdin /dev/stdout
+
+.PRECIOUS: gen/%/
+gen/%/:
+	mkdir -p $@
+
+.PRECIOUS: gen/%/typeinfo
+gen/%/typeinfo:	%.lc Makefile | gen/%/
+	$(LABCOMM) --typeinfo=$@ $<
+
+.PRECIOUS: gen/%/signatures.py
+gen/%/signatures.py: %.lc Makefile | gen/%/
+	$(LABCOMM) --python=$@ $<
+
+# C relay test rules
+.PRECIOUS: gen/%/c_code.h gen/%/c_code.c
+gen/%/c_code.h gen/%/c_code.c: %.lc Makefile | gen/%/
+	$(LABCOMM) --c=gen/$*/c_code.c --h=gen/$*/c_code.h $<
+
+.PRECIOUS: gen/%/c_relay.c
+gen/%/c_relay.c: gen/%/typeinfo relay_gen_c.py Makefile
+	./relay_gen_c.py $< > $@
+
+.PRECIOUS: gen/%/c_relay
+gen/%/c_relay: gen/%/c_relay.c gen/%/c_code.c Makefile
+	$(CC) $(CFLAGS) -o $@ $< -I../lib/c -I. \
+		-DLABCOMM_FD_OMIT_VERSION \
+		-DLABCOMM_ENCODER_LINEAR_SEARCH \
+		gen/$*/c_code.c \
+		../lib/c/labcomm.c \
+		../lib/c/labcomm_fd_*.c \
+		../lib/c/labcomm_dynamic_buffer_writer.c 
+
+# C# relay test rules
+.PRECIOUS: gen/%/cs_code.cs
+gen/%/cs_code.cs: %.lc Makefile | gen/%/
+	$(LABCOMM) --cs=$@ $<
+
+.PRECIOUS: gen/%/cs_relay.cs
+gen/%/cs_relay.cs:  gen/%/typeinfo relay_gen_cs.py Makefile
+	./relay_gen_cs.py $< > $@
+
+.PRECIOUS: gen/%/labcomm.dll
+gen/%/labcomm.dll:
+	ln -s ../../../lib/csharp/labcomm.dll $@
+
+.PRECIOUS: gen/%/cs_relay.exe
+gen/%/cs_relay.exe: gen/%/cs_relay.cs gen/%/cs_code.cs \
+		    gen/%/labcomm.dll Makefile
+	mcs -out:$@ $(filter %.cs, $^) -lib:../lib/csharp/ -r:labcomm
+
+# Java relay test rules
+.PRECIOUS: gen/%/java_code
+gen/%/java_code: %.lc | gen/%/
+	mkdir -p $@
+	$(LABCOMM) --java=$@ $<
+
diff --git a/test/basic.lc b/test/basic.lc
new file mode 100644
index 0000000..6c87af5
--- /dev/null
+++ b/test/basic.lc
@@ -0,0 +1,9 @@
+sample void s_void;
+sample byte s_byte;
+sample short s_short;
+sample int s_int;
+sample long s_long;
+sample float s_float;
+sample double s_double;
+sample boolean s_boolean;
+sample string s_string;
\ No newline at end of file
diff --git a/test/ccode.py b/test/ccode.py
deleted file mode 100644
index 4d15136..0000000
--- a/test/ccode.py
+++ /dev/null
@@ -1,22 +0,0 @@
-def gen(f, signatures):
-    print """
-#include <labcomm.h>
-#include <labcomm_fd_reader_writer.h>
-#include "%(f)s.h"
-""" % { 'f': f }
-    for s in [s.name for s in signatures]:
-        t = "%s_%s" % (f, s)
-        print """
-void handle_%(t)s(%(t)s *v, void *context)
-{
-  struct labcomm_encoder *e = context;
-
-  labcomm_encode_%(t)s(e, v);
-}
-""" % {'t':t}
-    print """
-int main(int argc, char *argv[]) {
-  struct labcomm_decoder *d;
-  struct labcomm_encoder *e;
-"""
-    
diff --git a/test/cscode.py b/test/cscode.py
deleted file mode 100755
index 073450b..0000000
--- a/test/cscode.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/python
-
-import os
-import re
-import subprocess
-import sys
-
-
-def gen(classname, namespace, signatures):
-    yield 'using System;'
-    yield 'using System.IO;'
-    yield 'using se.lth.control.labcomm;'
-    yield ''
-    yield 'class %s :' % classname
-    for s in signatures[0:-1]:
-        yield '%s%s.Handler,' % (namespace, s.name)
-    yield '%s%s.Handler' % (namespace, signatures[-1].name)
-    yield '{'
-    yield ''
-    yield '  LabCommEncoderChannel encoder;'
-    for s in signatures:
-        yield ''
-        if s.type == 'void':
-            yield '  void %s%s.Handler.handle() {' % ( namespace, s.name)
-        else:
-            yield '  void %s%s.Handler.handle(%s data) {' % (
-                namespace, s.name, s.type)
-        yield '    Console.Error.WriteLine("%s%s");' % (namespace, s.name)
-        if s.type == 'void':
-            yield '    %s%s.encode(encoder);' % (namespace, s.name)
-        else:
-            yield '    %s%s.encode(encoder, data);' % (namespace, s.name)
-        yield '  }'    
-    yield ''
-    yield '  public %s(String InName, String OutName) {' % (classname)
-    yield '    FileStream InFile = new FileStream(InName,' 
-    yield '                                       FileMode.Open, '
-    yield '                                       FileAccess.Read);'
-    yield '    LabCommDecoderChannel d = new LabCommDecoderChannel(InFile);'
-    yield '    FileStream OutFile = new FileStream(OutName, '
-    yield '                                        FileMode.OpenOrCreate, '
-    yield '                                        FileAccess.Write);'
-    yield '    encoder = new LabCommEncoderChannel(OutFile);'
-    yield ''
-    for s in signatures:
-        yield '    %s%s.register(d, this);' % (namespace, s.name)
-    yield ''
-    for s in signatures:
-        yield '    %s%s.register(encoder);' % (namespace, s.name)
-    yield ''
-    yield '    try {'
-    yield '      d.run();'
-    yield '    } catch (EndOfStreamException) {'
-    yield '    }'
-    yield ''
-    yield '  }'
-    yield ''
-    yield '  static void Main(String[] arg) {'
-    yield '    new %s(arg[0], arg[1]);' % (classname)
-    yield '  }'
-    yield ''
-    yield '}'
-
-class Signature:
-    def __init__(self, name, type):
-        self.name = name
-        self.type = type
-
-def test_program(target, typeinfo):
-    f = open(typeinfo)
-    signature = []
-    for l in f:
-        m = re.match('C#,sample,([^,]+),(.*)', l)
-        if m:
-            signature.append(Signature(m.group(1), m.group(2)))
-    f.close()
-    f = open(target, "w")
-    for l in gen("x", "", signature):
-        f.write(l + "\n")
-    f.close()
-   
-if __name__ == "__main__":
-    #os.system("labcomm --typeinfo=/dev/stdout %s" % sys.argv[1])
-    typeinfo = subprocess.Popen(["labcomm",
-                            "--typeinfo=/dev/stdout %s" % sys.argv[1]],
-                           stdout=subprocess.PIPE)
-    signature = []
-    for l in typeinfo.stdout:
-        m = re.match('C#,sample,([^,]+),(.*)', l)
-        if m:
-            signature.append(Signature(m.group(1), m.group(2)))
-    for l in gen("x", "", signature):
-        print l
-        
diff --git a/test/relay_gen_c.py b/test/relay_gen_c.py
new file mode 100755
index 0000000..a898d20
--- /dev/null
+++ b/test/relay_gen_c.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+
+import re
+import sys
+
+def split_match(pattern, multiline):
+    def match(s):
+        m = re.match(pattern, s)
+        if m:
+            return m.group(1)
+        pass
+    return filter(lambda s: s != None, map(match, multiline.split('\n')))
+   
+
+if __name__ == '__main__':
+    f = open(sys.argv[1])
+    sample = []
+    for l in map(lambda s: s.strip(), f):
+        lang,kind,func,arg = l[1:].split(l[0])
+        if lang == 'C' and kind == 'sample':
+            sample.append((func, arg))
+            pass
+        pass
+    result = []
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |#include <sys/types.h>
+      |#include <sys/stat.h>
+      |#include <fcntl.h>
+      |#include <labcomm.h>
+      |#include <labcomm_fd_reader.h>
+      |#include <labcomm_fd_writer.h>
+      |#include "c_code.h"
+    """))
+    for func,arg in sample:
+        result.extend(split_match('^[^|]*\|(.*)$', """
+          |void handle_%(func)s(%(arg)s *v, void *context)
+          |{
+          |  struct labcomm_encoder *e = context;
+          |  labcomm_encode_%(func)s(e, v);
+          |}""" % { 'func': func, 'arg': arg }))
+        pass
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |int main(int argc, char *argv[]) {
+      |  struct labcomm_encoder *e;
+      |  struct labcomm_decoder *d;
+      |  int in, out;
+      |  
+      |  if (argc < 3) { return 1; }
+      |  in = open(argv[1], O_RDONLY);
+      |  if (in < 0) { return 1; }
+      |  out = open(argv[2], O_WRONLY);
+      |  if (out < 0) { return 1; }
+      |  e = labcomm_encoder_new(labcomm_fd_writer, &out);
+      |  d = labcomm_decoder_new(labcomm_fd_reader, &in);
+    """))
+    for func,arg in sample:
+        result.extend(split_match('^[^|]*\|(.*)$', """
+          |  labcomm_encoder_register_%(func)s(e);
+          |  labcomm_decoder_register_%(func)s(d, handle_%(func)s, e);
+        """ % { 'func': func, 'arg': arg }))
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |  labcomm_decoder_run(d);
+      |  return 0;
+      |}
+    """))
+    print "\n".join(result)
+    pass
diff --git a/test/relay_gen_cs.py b/test/relay_gen_cs.py
new file mode 100755
index 0000000..0434c63
--- /dev/null
+++ b/test/relay_gen_cs.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+import re
+import sys
+
+def split_match(pattern, multiline):
+    def match(s):
+        m = re.match(pattern, s)
+        if m:
+            return m.group(1)
+        pass
+    return filter(lambda s: s != None, map(match, multiline.split('\n')))
+   
+
+if __name__ == '__main__':
+    f = open(sys.argv[1])
+    sample = []
+    for l in map(lambda s: s.strip(), f):
+        lang,kind,func,arg = l[1:].split(l[0])
+        if lang == 'C#' and kind == 'sample':
+            sample.append((func, arg))
+            pass
+        pass
+    result = []
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |using System;
+      |using System.IO;
+      |using se.lth.control.labcomm;
+      |
+      |public class cs_relay :
+    """))
+    for func,arg in sample[0:-1]:
+        result.append('  %s.Handler,' % func)
+        pass
+    result.append('  %s.Handler' % sample[-1][0])
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |{
+      |  LabCommEncoderChannel encoder;
+    """))
+    for func,arg in sample:
+        if arg == 'void':
+            result.extend(split_match('^[^|]*\|(.*)$', """
+              |  void %(func)s.Handler.handle() {
+              |    %(func)s.encode(encoder);
+              |  }
+            """ % { 'func': func}))
+            pass
+        else:
+            result.extend(split_match('^[^|]*\|(.*)$', """
+              |  void %(func)s.Handler.handle(%(arg)s data) {
+              |    %(func)s.encode(encoder, data);
+              |  }
+            """ % { 'func': func, 'arg': arg}))
+            pass
+        pass
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |  public cs_relay(String InName, String OutName) {
+      |    FileStream InFile = new FileStream(InName,
+      |                                       FileMode.Open,
+      |                                       FileAccess.Read);
+      |    LabCommDecoderChannel d = new LabCommDecoderChannel(InFile);
+      |    FileStream OutFile = new FileStream(OutName,
+      |                                        FileMode.OpenOrCreate,
+      |                                        FileAccess.Write);
+      |    encoder = new LabCommEncoderChannel(OutFile);
+      |
+    """))
+    for func,arg in sample:
+        result.append('    %s.register(d, this);' % func)
+        pass
+    for func,arg in sample:
+        result.append('    %s.register(encoder);' % func)
+        pass
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |    try {
+      |      d.run();
+      |    } catch (EndOfStreamException) {
+      |    }
+      |  }
+      |  static void Main(String[] arg) {
+      |    new cs_relay(arg[0], arg[1]);
+      |  }
+      |}
+    """))
+    print "\n".join(result)
+    exit(0)
+
+    for func,arg in sample:
+        result.extend(split_match('^[^|]*\|(.*)$', """
+          |void handle_%(func)s(%(arg)s *v, void *context)
+          |{
+          |  struct labcomm_encoder *e = context;
+          |  labcomm_encode_%(func)s(e, v);
+          |}""" % { 'func': func, 'arg': arg }))
+        pass
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |int main(int argc, char *argv[]) {
+      |  struct labcomm_encoder *e;
+      |  struct labcomm_decoder *d;
+      |  int in, out;
+      |  
+      |  if (argc < 3) { return 1; }
+      |  in = open(argv[1], O_RDONLY);
+      |  if (in < 0) { return 1; }
+      |  out = open(argv[2], O_WRONLY);
+      |  if (out < 0) { return 1; }
+      |  e = labcomm_encoder_new(labcomm_fd_writer, &out);
+      |  d = labcomm_decoder_new(labcomm_fd_reader, &in);
+    """))
+    for func,arg in sample:
+        result.extend(split_match('^[^|]*\|(.*)$', """
+          |  labcomm_encoder_register_%(func)s(e);
+          |  labcomm_decoder_register_%(func)s(d, handle_%(func)s, e);
+        """ % { 'func': func, 'arg': arg }))
+    result.extend(split_match('^[^|]*\|(.*)$', """
+      |  labcomm_decoder_run(d);
+      |  return 0;
+      |}
+    """))
+    print "\n".join(result)
+    pass
diff --git a/test/run b/test/run
deleted file mode 100755
index c0fff50..0000000
--- a/test/run
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/python
-# -*- coding: iso8859-15 -*-
-
-import math
-import os
-import sys
-import re
-import traceback
-import ccode
-import cscode
-
-def run_labcomm(base):
-    if not os.path.exists("gen/java/%s" % base):
-        os.makedirs("gen/java/%s" % base)
-    if not os.path.exists("gen/csharp"):
-        os.makedirs("gen/csharp")
-    if not os.path.exists("gen/c"):
-        os.makedirs("gen/c")
-    if not os.path.exists("gen/python"):
-        os.makedirs("gen/python")
-    cmd = " ".join([
-        "java -jar ../compiler/labComm.jar",
-        "--c=gen/c/%s.c" % base,
-        "--h=gen/c/%s.h" % base,
-        "--cs=gen/csharp/%s.cs" % base,
-        "--python=gen/python/%s.py" % base,
-        "--java=gen/java/%s" % base,
-        "--typeinfo=gen/%s.typeinfo" % base,
-        "%s.lc" % base
-        ])
-    err = os.system(cmd)
-    if err != 0:
-        sys.exit(err / 256)
-        
-class hexwriter(object):
-    def __init__(self, filename=None):
-        self.pos = 0
-        self.ascii = ''
-        if filename:
-            self.outfile = open(filename, "w")
-        else:
-            self.outfile = None
-
-    def write(self, data):
-        for c in data:
-            if ' ' <= c and c <= '}':
-                self.ascii += c
-            else:
-                self.ascii += '.'
-            sys.stdout.write("%2.2x " % ord(c))
-            self.pos += 1
-            if self.pos >= 15:
-                sys.stdout.write("%s\n" % self.ascii)
-                self.pos = 0
-                self.ascii = ""
-        self.outfile.write(data)
-        
-    def mark(self):
-        pass
-
-    def flush(self):
-        for i in range(self.pos, 15):
-            sys.stdout.write("   ")
-        sys.stdout.write("%s\n" % self.ascii)
-        self.pos = 0
-        self.ascii = ""
-        if self.outfile:
-            self.outfile.flush()
-
-
-def generate(decl):
-    if decl.__class__ == labcomm.sample:
-        result = []
-        for values in generate(decl.decl):
-            result.append((decl, values))
-        return result
-
-    elif decl.__class__ == labcomm.struct:
-        result = []
-        if len(decl.field) == 0:
-            result.append({})
-        else:
-            values1 = generate(decl.field[0][1])
-            values2 = generate(labcomm.struct(decl.field[1:]))
-            for v1 in values1:
-                for v2 in values2:
-                    v = dict(v2)
-                    v[decl.field[0][0]] = v1
-                    result.append(v)
-        return result
-    
-    elif decl.__class__ == labcomm.array:
-        if len(decl.indices) == 1:
-            values = generate(decl.decl)
-            if decl.indices[0] == 0:
-                lengths = [0, 1, 2]
-            else:
-                lengths = [ decl.indices[0] ]
-        else:
-            values = generate(labcomm.array(decl.indices[1:],decl.decl))
-            if decl.indices[0] == 0:
-                lengths = [1, 2]
-            else:
-                lengths = [ decl.indices[0] ]
-        result = []
-        for v in values:
-            for i in lengths:
-                element = []
-                for j in range(i):
-                    element.append(v)
-                result.append(element)
-        return result
-
-    elif decl.__class__ == labcomm.BOOLEAN:
-        return [False, True]
-
-    elif decl.__class__ == labcomm.BYTE:
-        return [-128, 0, 127]
-
-    elif decl.__class__ == labcomm.SHORT:
-        return [-32768, 0, 32767]
-
-    elif decl.__class__ == labcomm.INTEGER:
-        return [-2147483648, 0, 2147483647]
-
-    elif decl.__class__ == labcomm.LONG:
-        return [-9223372036854775808, 0, 9223372036854775807]
-
-    elif decl.__class__ == labcomm.FLOAT:
-        return [-math.pi, 0.0, math.pi]
-
-    elif decl.__class__ == labcomm.DOUBLE:
-        return [-math.pi, 0.0, math.pi]
-
-    elif decl.__class__ == labcomm.STRING:
-        return ['string',
-                'teckensträng'.decode("iso8859-15")]
-
-    print decl
-    raise Exception("unhandled decl %s" % decl.__class__)
-
-if __name__ == "__main__":
-    print os.getcwd(), sys.argv
-    if not os.path.exists("gen"):
-        os.makedirs("gen")
-    if len(sys.argv) > 1:
-        files = [s[0:-3] for s in sys.argv[1:] if s.endswith('.lc')]
-    else:
-        files = [s[0:-3] for s in os.listdir(".") if s.endswith('.lc')]
-
-    for f in files:
-        run_labcomm(f)
-
-    for f in files:
-        cscode.test_program("gen/csharp/test_%s.cs" % f,
-                            "gen/%s.typeinfo" % f)
-
-
-    sys.path.insert(0, "../lib/python")    
-    import labcomm;
-    sys.path.insert(0, "gen/python")    
-    for f in files:
-        print f
-        h = hexwriter("gen/%s.vec" % f)
-        encoder = labcomm.Encoder(h)
-        signatures = []
-        i = __import__(f)
-        for k in dir(i):
-            v = getattr(i, k)
-            try:
-                s = v.signature
-            except:
-                s = None
-            if s:
-                signatures.append(s)
-                encoder.add_decl(s)
-        for s in signatures:
-            for e in generate(s):
-                encoder.encode(e[1], s)
-
-        h.flush()
-
-        ccode.gen(f, signatures)
-        
-        
diff --git a/test/run.py b/test/run.py
deleted file mode 100755
index 6793aac..0000000
--- a/test/run.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/python
-# -*- coding: iso8859-15 -*-
-
-import math
-import os
-import sys
-import re
-import traceback
-
-def run_labcomm(base):
-    if not os.path.exists("gen/java/%s" % base):
-        os.makedirs("gen/java/%s" % base)
-    cmd = " ".join([
-        "java -jar ../compiler/labComm.jar",
-        "--c=gen/%s.c" % base,
-        "--h=gen/%s.h" % base,
-        "--python=gen/%s.py" % base,
-        "--java=gen/java/%s" % base,
-        "%s.lc" % base
-        ])
-    print cmd
-    os.system(cmd)
-    
-class hexwriter(object):
-    def __init__(self):
-        self.pos = 0
-        self.ascii = ''
-
-    def write(self, data):
-        for c in data:
-            if ' ' <= c and c <= '}':
-                self.ascii += c
-            else:
-                self.ascii += '.'
-            sys.stdout.write("%2.2x " % ord(c))
-            self.pos += 1
-            if self.pos >= 15:
-                sys.stdout.write("%s\n" % self.ascii)
-                self.pos = 0
-                self.ascii = ""
-
-    def mark(self):
-        pass
-
-    def flush(self):
-        for i in range(self.pos, 15):
-            sys.stdout.write("   ")
-        sys.stdout.write("%s\n" % self.ascii)
-        self.pos = 0
-        self.ascii = ""
-
-def generate(decl):
-    if decl.__class__ == labcomm.sample:
-        result = []
-        for values in generate(decl.decl):
-            result.append((decl, values))
-        return result
-
-    elif decl.__class__ == labcomm.struct:
-        result = []
-        if len(decl.field) == 0:
-            result.append({})
-        else:
-            values1 = generate(decl.field[0][1])
-            values2 = generate(labcomm.struct(decl.field[1:]))
-            for v1 in values1:
-                for v2 in values2:
-                    v = dict(v2)
-                    v[decl.field[0][0]] = v1
-                    result.append(v)
-        return result
-    
-    elif decl.__class__ == labcomm.array:
-        if len(decl.indices) == 1:
-            values = generate(decl.decl)
-            if decl.indices[0] == 0:
-                lengths = [0, 1, 2]
-            else:
-                lengths = [ decl.indices[0] ]
-        else:
-            values = generate(labcomm.array(decl.indices[1:],decl.decl))
-            if decl.indices[0] == 0:
-                lengths = [1, 2]
-            else:
-                lengths = [ decl.indices[0] ]
-        result = []
-        for v in values:
-            for i in lengths:
-                element = []
-                for j in range(i):
-                    element.append(v)
-                result.append(element)
-        return result
-
-    elif decl.__class__ == labcomm.BOOLEAN:
-        return [False, True]
-
-    elif decl.__class__ == labcomm.BYTE:
-        return [-128, 0, 127]
-
-    elif decl.__class__ == labcomm.SHORT:
-        return [-32768, 0, 32767]
-
-    elif decl.__class__ == labcomm.INTEGER:
-        return [-2147483648, 0, 2147483647]
-
-    elif decl.__class__ == labcomm.LONG:
-        return [-9223372036854775808, 0, 9223372036854775807]
-
-    elif decl.__class__ == labcomm.FLOAT:
-        return [-math.pi, 0.0, math.pi]
-
-    elif decl.__class__ == labcomm.DOUBLE:
-        return [-math.pi, 0.0, math.pi]
-
-    elif decl.__class__ == labcomm.STRING:
-        return ['string',
-                'teckensträng'.decode("iso8859-15")]
-
-    print decl
-    raise Exception("unhandled decl %s" % decl.__class__)
-
-if __name__ == "__main__":
-    sys.path.insert(0, "../lib/python/")    
-    import labcomm
-    print os.getcwd(), sys.argv
-    if not os.path.exists("gen"):
-        os.makedirs("gen")
-    files = sys.argv[1:]
-    print sys.argv, files
-    if len(files) == 0:
-        files = os.listdir(".")
-    for f in files:
-        m = re.match("(.*).lc", f)
-        if m:
-            run_labcomm(m.group(1))
-
-    sys.path.insert(0, "gen")    
-    for f in files:
-        m = re.match("(.*).lc", f)
-        if m:
-            print f
-            h = hexwriter()
-            encoder = labcomm.Encoder(h)
-            signatures = []
-            i = __import__(m.group(1))
-            for k in dir(i):
-                v = getattr(i, k)
-                try:
-                    s = v.signature
-                except:
-                    s = None
-                if s:
-                    signatures.append(s)
-                    encoder.add_decl(s)
-            for s in signatures:
-                for e in generate(s):
-                    encoder.encode(e[1], s)
-
-            h.flush()
diff --git a/test/test_encoder_decoder.py b/test/test_encoder_decoder.py
new file mode 100755
index 0000000..0f7f7ce
--- /dev/null
+++ b/test/test_encoder_decoder.py
@@ -0,0 +1,290 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import argparse
+import imp
+import labcomm
+import math
+import os
+import re
+import struct
+import subprocess
+import sys
+import threading
+
+class hexwriter(object):
+    def __init__(self, outfile):
+        self.pos = 0
+        self.ascii = ''
+        self.outfile = outfile
+
+    def write(self, data):
+        for c in data:
+            if ' ' <= c and c <= '}':
+                self.ascii += c
+            else:
+                self.ascii += '.'
+            sys.stdout.write("%2.2x " % ord(c))
+            self.pos += 1
+            if self.pos >= 15:
+                sys.stdout.write("%s\n" % self.ascii)
+                self.pos = 0
+                self.ascii = ""
+        #self.outfile.write(data)
+        
+    def mark(self):
+        self.flush()
+        pass
+
+    def flush(self):
+        for i in range(self.pos, 15):
+            sys.stdout.write("   ")
+        sys.stdout.write("%s\n" % self.ascii)
+        self.pos = 0
+        self.ascii = ""
+        if self.outfile:
+            self.outfile.flush()
+
+
+def generate(decl):
+    if decl.__class__ == labcomm.sample:
+        result = []
+        for values in generate(decl.decl):
+            result.append((decl, values))
+        return result
+
+    elif decl.__class__ == labcomm.struct:
+        result = []
+        if len(decl.field) == 0:
+            result.append({})
+        else:
+            values1 = generate(decl.field[0][1])
+            values2 = generate(labcomm.struct(decl.field[1:]))
+            for v1 in values1:
+                for v2 in values2:
+                    v = dict(v2)
+                    v[decl.field[0][0]] = v1
+                    result.append(v)
+        return result
+    
+    elif decl.__class__ == labcomm.array:
+        if len(decl.indices) == 1:
+            values = generate(decl.decl)
+            if decl.indices[0] == 0:
+                lengths = [0, 1, 2]
+            else:
+                lengths = [ decl.indices[0] ]
+        else:
+            values = generate(labcomm.array(decl.indices[1:],decl.decl))
+            if decl.indices[0] == 0:
+                lengths = [1, 2]
+            else:
+                lengths = [ decl.indices[0] ]
+        result = []
+        for v in values:
+            for i in lengths:
+                element = []
+                for j in range(i):
+                    element.append(v)
+                result.append(element)
+        return result
+
+    elif decl.__class__ == labcomm.BOOLEAN:
+        return [False, True]
+
+    elif decl.__class__ == labcomm.BYTE:
+        return [-128, 0, 127]
+
+    elif decl.__class__ == labcomm.SHORT:
+        return [-32768, 0, 32767]
+
+    elif decl.__class__ == labcomm.INTEGER:
+        return [-2147483648, 0, 2147483647]
+
+    elif decl.__class__ == labcomm.LONG:
+        return [-9223372036854775808, 0, 9223372036854775807]
+
+    elif decl.__class__ == labcomm.FLOAT:
+        def tofloat(v):
+            return struct.unpack('f', struct.pack('f', v))[0]
+        return [tofloat(-math.pi), 0.0, tofloat(math.pi)]
+
+    elif decl.__class__ == labcomm.DOUBLE:
+        return [-math.pi, 0.0, math.pi]
+
+    elif decl.__class__ == labcomm.STRING:
+        return ['string', u'sträng' ]
+
+    print decl
+    raise Exception("unhandled decl %s" % decl.__class__)
+
+def labcomm_compile(lc, name, args):
+    for lang in [ 'c', 'csharp', 'java', 'python']:
+        destdir = 'gen/%s/%s' % (name, lang)
+        if not os.path.exists(destdir):
+            os.makedirs(destdir)
+            pass
+        pass
+    cmd = args.labcomm.split() + [ 
+        "--c=gen/%s/c/%s.c" % (name, name),
+        "--h=gen/%s/c/%s.h" % (name, name),
+        "--cs=gen/%s/csharp/%s.cs" % (name, name),
+        "--python=gen/%s/python/%s.py" % (name, name),
+        "--java=gen/%s/java/" % name,
+        "--typeinfo=gen/%s/%s.typeinfo" % (name, name),
+        lc]
+    subprocess.check_call(cmd)
+    pass
+
+def get_signatures(path):
+    fp, pathname, description = imp.find_module(os.path.basename(path)[0:-3], 
+                                                [ os.path.dirname(path) ])
+    with fp as fp:
+        m = imp.load_module('signatures', fp, pathname, description)
+        pass
+    return m.signatures
+
+class Test:
+    
+    def __init__(self, program, signatures):
+        self.program = program
+        self.signatures = signatures
+        pass
+
+    def run(self):
+        print 'Testing', self.program
+        p = subprocess.Popen(self.program, 
+                             stdin=subprocess.PIPE,
+                             stdout=subprocess.PIPE)
+        self.expected = None
+        self.failed = False
+        self.next = threading.Semaphore(0)
+        decoder = threading.Thread(target=self.decode, args=(p.stdout,))
+        decoder.start()
+        class Writer:
+            def write(self, data):
+                p.stdin.write(data)
+                pass
+            def mark(self):
+                p.stdin.flush()
+                pass
+            pass
+        h = hexwriter(p.stdin)
+        encoder = labcomm.Encoder(Writer())
+        for name,signature in self.signatures:
+            encoder.add_decl(signature)
+            pass
+        print self.signatures
+        for name,signature in self.signatures:
+            print "Checking", name,
+            sys.stdout.flush()
+            for decl,value in generate(signature):
+                sys.stdout.write('.')
+                #print name,decl,value,value.__class__
+                self.expected = value
+                encoder.encode(value, decl)
+                self.next.acquire()
+                if self.failed:
+                    p.terminate()
+                    exit(1)
+                pass
+            print
+            pass
+        p.stdin.close()
+        print p.wait()
+        pass
+
+    def decode(self, f):
+        class Reader:
+            def read(self, count):
+                result = f.read(count)
+                if len(result) == 0:
+                    raise EOFError()
+                return result
+            def mark(self, value, decl):
+                pass
+            pass
+        decoder = labcomm.Decoder(Reader())
+        try:
+            while True:
+                value,decl = decoder.decode()
+                if value != None:
+                    if value != self.expected:
+                        print "Coding error", value, self.expected, decl
+                        self.failed = True
+                    self.next.release()
+                pass
+            pass
+        except EOFError:
+            pass
+        print 'Done'
+        pass
+
+    pass
+    
+def run(test, signatures):
+    t = Test(test, signatures)
+    t.run()
+    pass
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Run encoding test.')
+    class test_action(argparse.Action):
+        def __call__(self, parser, namespace, values, option_string=None):
+            old = getattr(namespace, self.dest)
+            old.append(values)
+    parser.add_argument('--signatures')
+    parser.add_argument('--test', nargs='*', action=test_action, default=[])
+
+    args = parser.parse_args()
+    signatures = get_signatures(args.signatures)
+    for test in args.test:
+        run(test, signatures)
+    exit(0)
+    
+    for lc in args.lc:
+        run(lc, args)
+        pass
+    exit(0)
+
+
+    print os.getcwd(), sys.argv
+    if not os.path.exists("gen"):
+        os.makedirs("gen")
+    if len(sys.argv) > 1:
+        files = [s[0:-3] for s in sys.argv[1:] if s.endswith('.lc')]
+    else:
+        files = [s[0:-3] for s in os.listdir(".") if s.endswith('.lc')]
+
+    for f in files:
+        cscode.test_program("gen/csharp/test_%s.cs" % f,
+                            "gen/%s.typeinfo" % f)
+
+
+    sys.path.insert(0, "../lib/python")    
+    import labcomm;
+    sys.path.insert(0, "gen/python")    
+    for f in files:
+        print f
+        h = hexwriter("gen/%s.vec" % f)
+        encoder = labcomm.Encoder(h)
+        signatures = []
+        i = __import__(f)
+        for k in dir(i):
+            v = getattr(i, k)
+            try:
+                s = v.signature
+            except:
+                s = None
+            if s:
+                signatures.append(s)
+                encoder.add_decl(s)
+        for s in signatures:
+            for e in generate(s):
+                encoder.encode(e[1], s)
+
+        h.flush()
+
+        ccode.gen(f, signatures)
+        
+        
diff --git a/test/test_simple.c b/test/test_simple.c
deleted file mode 100644
index 22aa670..0000000
--- a/test/test_simple.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <labcomm.h>
-#include <labcomm_fd_reader_writer.h>
-#include "gen/simple.h"
-
-void simple_an_int_handler(simple_an_int *v,
-		      void *context)
-{
-  struct labcomm_encoder *e = context;
-
-  labcomm_encode_simple_an_int(e, v);
-}
-
-int main(int argc, char *argv[]) {
-  struct labcomm_decoder *d;
-  struct labcomm_encoder *e;
-
-  labcomm_decoder_register_simple_an_int(d, simple_an_int_handler, e);
-  return 0;
-}
-- 
GitLab