diff --git a/compiler/build.xml b/compiler/build.xml index 932ba0441be5534fa1e5518f953f4ea1c976d636..ff8cf2aa16f4d392dba1f47d5e38e9faac95dbab 100644 --- a/compiler/build.xml +++ b/compiler/build.xml @@ -4,7 +4,7 @@ clean - removes all generated files and class files Targets for working from Eclipse: gen - generates java files - genClean - removes all generated files and their class files + cleanGen - removes all generated files and their class files --> <project name="LabComm" default="build" basedir="."> @@ -77,7 +77,9 @@ classpath="tools/jastadd2.jar"/> <!-- delete all .class files recursively --> <delete> <fileset dir="." includes="**/*.class"/> + <fileset dir="." includes="labComm.jar"/> </delete> + </target> diff --git a/examples/simple/compile.sh b/examples/simple/compile.sh index 468f77ef760a0591e9a6643a570f6af3263f40fe..cd7729c2da8ed0e3ca6f8387b65326c1de5eed0d 100644 --- a/examples/simple/compile.sh +++ b/examples/simple/compile.sh @@ -1,4 +1,4 @@ -(cd ../../lib/c; make) +(cd ../../lib/c; make -e LABCOMM_NO_EXPERIMENTAL=true) (cd ../../compiler ; ant jar) java -jar ../../compiler/labComm.jar --java=gen --c=gen/simple.c --h=gen/simple.h --python=gen/simple.py simple.lc diff --git a/examples/wiki_example/data.java b/examples/wiki_example/data.java index ce225eae8310622166e4babeda1943c26e52cb61..7acf55a5a1c915dc72ed235b9d3a88cd45ad8b5d 100644 --- a/examples/wiki_example/data.java +++ b/examples/wiki_example/data.java @@ -56,7 +56,7 @@ public class data implements LabCommSample { } private static byte[] signature = new byte[] { - 0, 0, 0, 37, + 37, }; } diff --git a/examples/wiki_example/example.c b/examples/wiki_example/example.c index 4b6f639c492e0c24a54997beb688aadd20f56600..827f4e3effa68fe0f674106b1676f1ccd12a9a4f 100644 --- a/examples/wiki_example/example.c +++ b/examples/wiki_example/example.c @@ -4,30 +4,30 @@ static unsigned char signature_bytes_log_message[] = { // struct { 2 fields -0, 0, 0, 17, - 0, 0, 0, 2, +17, + 2, // int 'sequence' - 0, 0, 0, 8, + 8, 115, 101, 113, 117, 101, 110, 99, 101, - 0, 0, 0, 35, + 35, // array [_] 'line' - 0, 0, 0, 4, + 4, 108, 105, 110, 101, // array [_] - 0, 0, 0, 16, - 0, 0, 0, 1, - 0, 0, 0, 0, + 16, + 1, + 0, // struct { 2 fields - 0, 0, 0, 17, - 0, 0, 0, 2, + 17, + 2, // boolean 'last' - 0, 0, 0, 4, + 4, 108, 97, 115, 116, - 0, 0, 0, 32, + 32, // string 'data' - 0, 0, 0, 4, + 4, 100, 97, 116, 97, - 0, 0, 0, 39, + 39, // } // } // } @@ -39,7 +39,7 @@ labcomm_signature_t labcomm_signature_example_log_message = { signature_bytes_log_message }; static unsigned char signature_bytes_data[] = { -0, 0, 0, 37, +37, }; labcomm_signature_t labcomm_signature_example_data = { LABCOMM_SAMPLE, "data", @@ -58,7 +58,7 @@ static void decode_log_message( { example_log_message v; v.sequence = labcomm_decode_int(d); - v.line.n_0 = labcomm_decode_int(d); + v.line.n_0 = labcomm_decode_packed32(d); v.line.a = malloc(sizeof(v.line.a[0]) * v.line.n_0); { int i_0_0; @@ -106,7 +106,7 @@ static void encode_log_message( labcomm_encode_type_index(e, &labcomm_signature_example_log_message); { labcomm_encode_int(e, (*v).sequence); - labcomm_encode_int(e, (*v).line.n_0); + labcomm_encode_packed32(e, (*v).line.n_0); { int i_0_0; for (i_0_0 = 0 ; i_0_0 < (*v).line.n_0 ; i_0_0++) { diff --git a/examples/wiki_example/example.encoded b/examples/wiki_example/example.encoded index fe3d4eb2a5acba9e220ffd62cef467eb02850fdb..6cd2cd814a2721384a24d02bd60685d11b0df634 100644 Binary files a/examples/wiki_example/example.encoded and b/examples/wiki_example/example.encoded differ diff --git a/lib/c/Makefile b/lib/c/Makefile index 4d7117ed6f12b6fc6113a486daa67fe5ccdf81e0..a17c72d4a7f6807c43c630da5095d5e8392d96dd 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -1,22 +1,85 @@ -CC = gcc -CFLAGS = -g -I . +## Macros -liblabcomm.a : labcomm.o labcomm_fd_reader_writer.o experimental/labcomm_udp_reader_writer.o \ - experimental/udp_hack.o experimental/ethaddr.o \ - experimental/labcomm_thr_reader_writer.o \ - experimental/ThrottleDrv/ethernet_drv.o experimental/ThrottleDrv/throttle_drv.o +# Use LLVM clang if it's found. +CC = $(shell hash clang 2>/dev/null && echo clang || echo gcc) +CFLAGS = -g -Wall -I . +LDFLAGS = -L . +LDLIBS_TEST = -lcunit -llabcomm + +OBJS= labcomm.o labcomm_fd_reader_writer.o labcomm_mem_reader.o labcomm_mem_writer.o +LABCOMMC_PATH=../../compiler +LABCOMMC_JAR=$(LABCOMMC_PATH)/labComm.jar + +TEST_DIR=test +TESTDATA_DIR=$(TEST_DIR)/testdata +TEST_GEN_DIR=$(TESTDATA_DIR)/gen + +CREATED_DIRS=$(TEST_DIR) $(TESTDATA_DIR) $(TEST_GEN_DIR) + +# Disable experimental objects by invoking make like `make -e LABCOMM_NO_EXPERIMENTAL=true` +ifneq ($(LABCOMM_NO_EXPERIMENTAL),true) + OBJS += experimental/udp_hack.o experimental/ethaddr.o \ + experimental/labcomm_thr_reader_writer.o \ + experimental/ThrottleDrv/ethernet_drv.o \ + experimental/ThrottleDrv/throttle_drv.o \ + experimental/labcomm_udp_reader_writer.o +endif + +## Targets + +.PHONY: all run-test clean distclean + +all: liblabcomm.a test/test_labcomm_errors + +liblabcomm.a: $(OBJS) ar -r liblabcomm.a $^ + labcomm.o : labcomm.c labcomm.h labcomm_private.h labcomm_fd_reader_writer.o : labcomm_fd_reader_writer.c labcomm_fd_reader_writer.h labcomm.h labcomm_private.h +labcomm_mem_reader.o: labcomm_fd_reader_writer.c labcomm_fd_reader_writer.h + +labcomm_mem_writer.o: labcomm_mem_writer.c labcomm_mem_writer.h cppmacros.h + ethaddr.o: ethaddr.c -%o: %c %h +$(CREATED_DIRS): + mkdir -p $@ + +run-test: $(TEST_DIR)/test_labcomm_errors |$(TEST_DIR) + test/test_labcomm_errors + +$(TEST_DIR)/test_labcomm_errors: $(TEST_DIR)/test_labcomm_errors.o liblabcomm.a |$(TEST_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -llabcomm -o $@ $^ + +$(TEST_DIR)/test_labcomm_errors.o: $(TEST_DIR)/test_labcomm_errors.c $(TEST_DIR)/test_labcomm_errors.h |$(TEST_DIR) + cd test; $(CC) $(CFLAGS) -I .. -c $(patsubst $(TEST_DIR)/%, %, $^) + +$(TEST_DIR)/test_labcomm.o: $(TEST_DIR)/test_labcomm.c $(TEST_GEN_DIR)/test_sample.h |$(TEST_DIR) + $(CC) -c $(CFLAGS) -o $@ $< + +$(TEST_DIR)/test_labcomm: $(TEST_DIR)/test_labcomm.o $(TEST_GEN_DIR)/test_sample.o liblabcomm.a + $(CC) $(CFLAGS) $(LDFLAGS) $(filter-out %.a,$^) $(LDLIBS) $(LDLIBS_TEST) -o $@ + +$(TEST_GEN_DIR)/%.c $(TEST_GEN_DIR)/%.h: $(TESTDATA_DIR)/%.lc $(LABCOMMC_JAR) |$(TEST_GEN_DIR) + java -jar $(LABCOMMC_JAR) --c=$(patsubst %.h,%.c,$@) --h=$(patsubst %.c,%.h,$@) $< + +$(LABCOMMC_JAR): + @echo "======Building LabComm compiler======" + cd $(LABCOMMC_PATH); ant jar + @echo "======End building LabComm compiler======" + +%.o: %.c %.h clean: - rm *.o experimental/*.o experimental/ThrottleDrv/*.o + $(RM) *.o + $(RM) experimental/*.o experimental/ThrottleDrv/*.o + $(RM) test/*.o + $(RM) test/*.gch + $(RM) test/test_labcomm_errors + $(RM) $(TEST_DIR)/test_labcomm distclean: clean - rm liblabcomm.a + $(RM) liblabcomm.a diff --git a/lib/c/cppmacros.h b/lib/c/cppmacros.h new file mode 100644 index 0000000000000000000000000000000000000000..a3e446b0a76d4e3218d9146dc929473ebd68f9c0 --- /dev/null +++ b/lib/c/cppmacros.h @@ -0,0 +1,8 @@ +// C Preprocessor macros. +#ifndef CPP_MACROS_H +#define CPP_MACROS_H + +#define X_EMPTY(mac) var ## 1 +#define EMPTY(mac) X_EMPTY(mac) // Returns 1 if macro mac is empty. + +#endif diff --git a/lib/c/experimental/ThrottleDrv/display.h b/lib/c/experimental/ThrottleDrv/display.h index f8bed7568b1bd6284f8d09779732c04242529579..49c9cd4c84c02df8710685d301237fbb6492d137 100644 --- a/lib/c/experimental/ThrottleDrv/display.h +++ b/lib/c/experimental/ThrottleDrv/display.h @@ -1,7 +1,12 @@ #define PC_MODE #ifdef PC_MODE -#include <stdio.h> #define DISPLAY_ERR(s) perror(s); + +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif + #else #define DISPLAY_ERR(s) ; #endif diff --git a/lib/c/experimental/ThrottleDrv/ethernet_drv.c b/lib/c/experimental/ThrottleDrv/ethernet_drv.c index fe0004cad4ff5bcb6819fd500db5bc0b27f05393..9b4126eeee3befc7403c036dbab08dbc413fdb44 100644 --- a/lib/c/experimental/ThrottleDrv/ethernet_drv.c +++ b/lib/c/experimental/ThrottleDrv/ethernet_drv.c @@ -1,7 +1,6 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <stdio.h> #include <errno.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -14,6 +13,10 @@ #include "ethernet_drv.h" #include "display.h" +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif /** LOCAL FUNCTIONS **/ diff --git a/lib/c/experimental/ethaddr.c b/lib/c/experimental/ethaddr.c index b2207e5f52537abed048192850f5d447185e13c2..5aed408adc13df509d9e6956bb2a2a846ed3301c 100644 --- a/lib/c/experimental/ethaddr.c +++ b/lib/c/experimental/ethaddr.c @@ -1,6 +1,10 @@ -#include <stdio.h> #include "ethaddr.h" +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif + #if ETH_ALEN != 6 #warning "Assumption that ETH_ALEN == 6 appears false. Here be dragons." #endif diff --git a/lib/c/experimental/udp_hack.c b/lib/c/experimental/udp_hack.c index f4670bb3495f6d53d3544b5c70a6ed3850683e64..1d26eb7d838b8c4781a6b623e560cb5e71beeca1 100644 --- a/lib/c/experimental/udp_hack.c +++ b/lib/c/experimental/udp_hack.c @@ -1,11 +1,15 @@ #include <arpa/inet.h> #include <netinet/in.h> -#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif + #define BUFLEN 512 #define NPACK 10 #define PORT 9930 diff --git a/lib/c/labcomm.c b/lib/c/labcomm.c index b67be7ad7da55a96100385603a3066da53c4ab92..ac8cf561b5df02c2b9003b763d03ac5a36d805f8 100644 --- a/lib/c/labcomm.c +++ b/lib/c/labcomm.c @@ -1,18 +1,32 @@ #include <errno.h> #include <string.h> -#include <stdio.h> + #ifndef __VXWORKS__ -#include <strings.h> + #ifdef ARM_CORTEXM3_CODESOURCERY + #include <string.h> + #else + #include <strings.h> + #endif #endif -#include <stdlib.h> -#ifdef __VXWORKS__ -#if (CPU == PPC603) -#undef _LITTLE_ENDIAN + +#ifndef ARM_CORTEXM3_CODESOURCERY + #include <stdlib.h> #endif -#if (CPU == PENTIUM4) -#undef _BIG_ENDIAN + +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> #endif + +#ifdef __VXWORKS__ + #if (CPU == PPC603) + #undef _LITTLE_ENDIAN + #endif + #if (CPU == PENTIUM4) + #undef _BIG_ENDIAN + #endif #endif + #include "labcomm.h" #include "labcomm_private.h" @@ -35,6 +49,83 @@ typedef struct labcomm_decoder_context { labcomm_sample_entry_t *sample; } labcomm_decoder_context_t; +void labcomm_register_error_handler_encoder(struct labcomm_encoder *encoder, labcomm_error_handler_callback callback) +{ + encoder->on_error = callback; + encoder->writer.on_error = callback; +} + +void labcomm_register_error_handler_decoder(struct labcomm_decoder *decoder, labcomm_error_handler_callback callback) +{ + decoder->on_error = callback; + decoder->reader.on_error = callback; +} + +/* Error strings. _must_ be the same order as in enum labcomm_error */ +const char *labcomm_error_strings[] = { + "Enum begin guard. DO NO use this as an error.", + "Encoder has no registration for this signature.", + "Encoder is missing do_register", + "Encoder is missing do_encode", + "The labcomm buffer is full and it.", + "Decoder is missing do_register", + "Decoder is missing do_decode_one", + "Decoder: Unknown datatype", + "Decoder: index mismatch", + "Decoder: type not found", + "This function is not yet implemented.", + "User defined error.", + "Could not allocate memory.", + "Enum end guard. DO NO use this as an error." +}; + +const char *labcomm_error_get_str(enum labcomm_error error_id) +{ + const char *error_str = NULL; + // Check if this is a known error ID. + if (error_id >= LABCOMM_ERROR_ENUM_BEGIN_GUARD && error_id <= LABCOMM_ERROR_ENUM_END_GUARD) { + error_str = labcomm_error_strings[error_id]; + } + return error_str; +} + +void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d, labcomm_handle_new_datatype_callback on_new_datatype) +{ + d->on_new_datatype = on_new_datatype; +} + +int on_new_datatype(labcomm_decoder_t *d, labcomm_signature_t *sig) +{ + d->on_error(LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, 4, "%s(): unknown datatype '%s'\n", __FUNCTION__, sig->name); + return 0; +} + +void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...) +{ +#ifndef LABCOMM_NO_STDIO + const char *err_msg = labcomm_error_get_str(error_id); // The final string to print. + if (err_msg == NULL) { + err_msg = "Error with an unknown error ID occured."; + } + fprintf(stderr, "%s\n", err_msg); + + if (nbr_va_args > 0) { + va_list arg_pointer; + va_start(arg_pointer, nbr_va_args); + + fprintf(stderr, "%s\n", "Extra info {"); + char *print_format = va_arg(arg_pointer, char *); + vfprintf(stderr, print_format, arg_pointer); + fprintf(stderr, "}\n"); + + va_end(arg_pointer); + } +#else + ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting. +#endif +} + + static labcomm_sample_entry_t *get_sample_by_signature_address( labcomm_sample_entry_t *head, labcomm_signature_t *signature) @@ -135,7 +226,7 @@ static void do_encode( if (sample && sample->encode) { sample->encode(encoder, value); } else { - printf("Encoder has no registration for %s\n", signature->name); + encoder->on_error(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, 2, "No registration for %s.\n", signature->name); } } @@ -148,7 +239,7 @@ labcomm_encoder_t *labcomm_encoder_new( labcomm_encoder_context_t *context; context = malloc(sizeof(labcomm_encoder_context_t)); - context->sample = 0; + context->sample = NULL; context->index = LABCOMM_USER; result->context = context; result->writer.context = writer_context; @@ -158,8 +249,10 @@ labcomm_encoder_t *labcomm_encoder_new( result->writer.pos = 0; result->writer.write = writer; result->writer.write(&result->writer, labcomm_writer_alloc); + result->writer.on_error = on_error_fprintf; result->do_register = do_encoder_register; result->do_encode = do_encode; + result->on_error = on_error_fprintf; } return result; } @@ -169,10 +262,11 @@ void labcomm_internal_encoder_register( labcomm_signature_t *signature, labcomm_encode_typecast_t encode) { - if (e && e->do_register) { + // Will segfault if e == NULL. + if (e->do_register) { e->do_register(e, signature, encode); } else { - printf("Encoder is missing do_register\n"); + e->on_error(LABCOMM_ERROR_ENC_MISSING_DO_REG, 0); } } @@ -181,10 +275,11 @@ void labcomm_internal_encode( labcomm_signature_t *signature, void *value) { - if (e && e->do_encode) { + // Will segfault if e == NULL + if (e->do_encode) { e->do_encode(e, signature, value); } else { - printf("Encoder is missing do_encode\n"); + e->on_error(LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, 0); } } @@ -196,8 +291,18 @@ void labcomm_internal_encoder_user_action(labcomm_encoder_t *e, void labcomm_encoder_free(labcomm_encoder_t* e) { - e->writer.write(&e->writer, labcomm_writer_free); + labcomm_encoder_context_t *econtext = (labcomm_encoder_context_t *) e->context; + + labcomm_sample_entry_t *sentry = econtext->sample; + labcomm_sample_entry_t *sentry_next; + while (sentry != NULL) { + sentry_next = sentry->next; + free(sentry); + sentry = sentry_next; + } + + free(e->context); free(e); } @@ -253,7 +358,8 @@ static void collect_flat_signature( int type = labcomm_decode_packed32(decoder); // printf("%s: type=%x\n", __FUNCTION__, type); if (type >= LABCOMM_USER) { - printf("Implement %s ... (1) for type 0x%x\n", __FUNCTION__, type); + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s ... (1) for type 0x%x\n", __FUNCTION__, type); } else { //labcomm_encode_int(signature_writer, type); labcomm_encode_packed32(signature_writer, type); @@ -292,7 +398,8 @@ static void collect_flat_signature( case LABCOMM_STRING: { } break; default: { - printf("Implement %s (2) for type 0x%x...\n", __FUNCTION__, type); + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s (2) for type 0x%x...\n", __FUNCTION__, type); } break; } } @@ -351,12 +458,12 @@ static int do_decode_one(labcomm_decoder_t *d) entry = get_sample_by_signature_value(context->sample, &signature); if (! entry) { // Unknown datatype, bail out - fprintf(stderr, "%s: unknown datatype '%s' (id=0x%x)\n", - __FUNCTION__, signature.name, index); + /*d->on_error(LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, 4, "%s(): unknown datatype '%s' (id=0x%x)\n", __FUNCTION__, signature.name, index);*/ + d->on_new_datatype(d, &signature); } else if (entry->index && entry->index != index) { - fprintf(stderr, "%s: index mismatch '%s' (id=0x%x != 0x%x)\n", - __FUNCTION__, signature.name, entry->index, index); + d->on_error(LABCOMM_ERROR_DEC_INDEX_MISMATCH, 5, "%s(): index mismatch '%s' (id=0x%x != 0x%x)\n", __FUNCTION__, signature.name, entry->index, index); } else { + // TODO unnessesary, since entry->index == index in above if statement entry->index = index; } free(signature.name); @@ -371,8 +478,9 @@ static int do_decode_one(labcomm_decoder_t *d) entry = get_sample_by_index(context->sample, result); if (!entry) { - fprintf(stderr, "%s: type not found (id=0x%x)\n", - __FUNCTION__, result); + // printf("Error: %s: type not found (id=0x%x)\n", + //__FUNCTION__, result); + d->on_error(LABCOMM_ERROR_DEC_TYPE_NOT_FOUND, 3, "%s(): type not found (id=0x%x)\n", __FUNCTION__, result); result = -ENOENT; } else { entry->decoder(d, entry->handler, entry->context); @@ -401,8 +509,11 @@ labcomm_decoder_t *labcomm_decoder_new( result->reader.pos = 0; result->reader.read = reader; result->reader.read(&result->reader, labcomm_reader_alloc); + result->reader.on_error = on_error_fprintf; result->do_register = do_decoder_register; result->do_decode_one = do_decode_one; + result->on_error = on_error_fprintf; + result->on_new_datatype = on_new_datatype; } return result; } @@ -414,23 +525,25 @@ void labcomm_internal_decoder_register( labcomm_handler_typecast_t handler, void *handler_context) { - if (d && d->do_register) { + // Will segfault if d == NULL + if (d->do_register) { d->do_register(d, signature, type_decoder, handler, handler_context); } else { - printf("Decoder is missing do_register\n"); + d->on_error(LABCOMM_ERROR_DEC_MISSING_DO_REG, 0); } } int labcomm_decoder_decode_one(labcomm_decoder_t *d) { int result = -1; - if (d && d->do_decode_one) + // Will segfault if decoder == NULL. + if (d->do_decode_one) { result = d->do_decode_one(d); } else { - printf("Decoder is missing do_decode_one\n"); + d->on_error(LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE, 0); } return result; } @@ -444,5 +557,16 @@ void labcomm_decoder_run(labcomm_decoder_t *d) void labcomm_decoder_free(labcomm_decoder_t* d) { d->reader.read(&d->reader, labcomm_reader_free); + labcomm_decoder_context_t *context = (labcomm_decoder_context_t *) d->context; + labcomm_sample_entry_t *entry = context->sample; + labcomm_sample_entry_t *entry_next; + + while (entry != NULL) { + entry_next = entry->next; + free(entry); + entry = entry_next; + } + + free(d->context); free(d); } diff --git a/lib/c/labcomm.h b/lib/c/labcomm.h index 9fed6976f1d5760b60b36213578e70d4ab89d2ce..5763b8d30975598e071b42a6429d35e6683081f5 100644 --- a/lib/c/labcomm.h +++ b/lib/c/labcomm.h @@ -1,10 +1,24 @@ #ifndef _LABCOMM_H_ #define _LABCOMM_H_ -#include <endian.h> -#include <stdio.h> +#ifdef ARM_CORTEXM3_CODESOURCERY + #include <machine/endian.h> +#else + #include <endian.h> +#endif + +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif + #include <stdlib.h> #include <string.h> +#include <stdarg.h> + +/* Forward declaration */ +struct labcomm_encoder; +struct labcomm_decoder; /* * Signature entry @@ -17,11 +31,62 @@ typedef struct { unsigned char *signature; } labcomm_signature_t; +/* + * Error handling. + */ + +/* Error IDs */ +enum labcomm_error { + LABCOMM_ERROR_ENUM_BEGIN_GUARD, // _must_ be the first enum element. labcomm_error_get_str() depends on this. + LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, + LABCOMM_ERROR_ENC_MISSING_DO_REG, + LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, + LABCOMM_ERROR_ENC_BUF_FULL, + LABCOMM_ERROR_DEC_MISSING_DO_REG, + LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE, + LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, + LABCOMM_ERROR_DEC_INDEX_MISMATCH, + LABCOMM_ERROR_DEC_TYPE_NOT_FOUND, + LABCOMM_ERROR_UNIMPLEMENTED_FUNC, + LABCOMM_ERROR_MEMORY, + LABCOMM_ERROR_USER_DEF, + LABCOMM_ERROR_ENUM_END_GUARD // _must_ be the last enum element. labcomm_error_get_str() depends on this. +}; + +/* Error strings. _must_ be the same order as in enum labcomm_error */ +extern const char *labcomm_error_strings[]; + +/* The callback prototype for error handling.\ + * First parameter is the error ID. + * The second paramters is the number of va_args that comes after this one. If noneit should be 0. + * Optionaly other paramters can be supplied depending on what is needed for this error ID. + */ +typedef void (* labcomm_error_handler_callback)(enum labcomm_error error_id, size_t nbr_va_args, ...); + +/* Default error handler, prints message to stderr. + * Extra info about the error can be supplied as char* as VA-args. Especially user defined errors should supply a describing string. if nbr_va_args > 1 the first variable argument must be a printf format string and the possibly following arguments are passed as va_args to vprintf. + */ +void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...); + +/* Register a callback for the error handler for this encoder. */ +void labcomm_register_error_handler_encoder(struct labcomm_encoder *encoder, labcomm_error_handler_callback callback); + +/* Register a callback for the error handler for this decoder. */ +void labcomm_register_error_handler_decoder(struct labcomm_decoder *decoder, labcomm_error_handler_callback callback); + +/* Get a string describing the supplied standrad labcomm error. */ +const char *labcomm_error_get_str(enum labcomm_error error_id); + +typedef int (* labcomm_handle_new_datatype_callback)(struct labcomm_decoder *decoder, + labcomm_signature_t *sig); + +void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d, + labcomm_handle_new_datatype_callback on_new_datatype); + /* * Decoder */ -struct labcomm_decoder; typedef enum { labcomm_reader_alloc, @@ -38,6 +103,7 @@ typedef struct labcomm_reader { int count; int pos; int (*read)(struct labcomm_reader *, labcomm_reader_action_t); + labcomm_error_handler_callback on_error; } labcomm_reader_t; struct labcomm_decoder *labcomm_decoder_new( @@ -53,7 +119,6 @@ void labcomm_decoder_free( /* * Encoder */ -struct labcomm_encoder; typedef enum { labcomm_writer_alloc, @@ -71,9 +136,9 @@ typedef struct labcomm_writer { int count; int pos; int (*write)(struct labcomm_writer *, labcomm_writer_action_t); + labcomm_error_handler_callback on_error; } labcomm_writer_t; -struct labcomm_encoder; struct labcomm_encoder *labcomm_encoder_new( int (*writer)(labcomm_writer_t *, labcomm_writer_action_t), void *writer_context); diff --git a/lib/c/labcomm_mem_reader.c b/lib/c/labcomm_mem_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..088123d0eb1c57b0ecd322559087ac80df6e5b49 --- /dev/null +++ b/lib/c/labcomm_mem_reader.c @@ -0,0 +1,73 @@ +#include "labcomm_mem_reader.h" + +#include <errno.h> + +/* This implementation assumes labcomm will call end exactly once after each start + * It is not allowed to save data in mcontext->enc_data, + * this pointer will be set to NULL after decoding. + */ +/* NOTE!!!! + * start will be run first, once a signature or a data section is decoded + * end will be run and then start again. If end of encoded data is reached this + * must be handled in start. + */ + +// TODO make labcomm use result! +int labcomm_mem_reader(labcomm_reader_t *r, labcomm_reader_action_t action) +{ + int result = -EINVAL; + labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) r->context; + + switch (action) { + case labcomm_reader_alloc: { + r->data = NULL; + r->data_size = 0; + r->pos = 0; + r->count = 0; + } break; + case labcomm_reader_start: { + if (r->data == NULL && mcontext->enc_data != NULL) { + r->data = (unsigned char *) malloc(mcontext->size); + if(r->data != NULL) { + memcpy(r->data, mcontext->enc_data, mcontext->size); + r->data_size = mcontext->size; + r->count = mcontext->size; + r->pos = 0; + result = r->data_size; + } else { + r->data_size = 0; + result = -ENOMEM; + } + } else if (r->data == NULL && mcontext->enc_data == NULL) { + result = -1; + } else { + result = r->count - r->pos; + } + } break; + case labcomm_reader_continue: { + if (r->pos < r->count) { + result = r->count - r->pos; + } else { + // TODO set some describing error here + result = -1; + } + } break; + case labcomm_reader_end: { + if (r->pos >= r->count) { + free(r->data); + r->data = NULL; + r->data_size = 0; + mcontext->enc_data = NULL; + mcontext->size = 0; + } + result = r->count - r->pos; + } break; + case labcomm_reader_free: { + r->count = 0; + r->pos = 0; + result = 0; + } break; + } + return result; +} + diff --git a/lib/c/labcomm_mem_reader.h b/lib/c/labcomm_mem_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..5cac018ff362c1c9ecfc7984c410b71d01e0016b --- /dev/null +++ b/lib/c/labcomm_mem_reader.h @@ -0,0 +1,17 @@ +#ifndef LABCOMM_MEM_READER_H +#define LABCOMM_MEM_READER_H + +#include "labcomm.h" + +/* enc_data: The data to be decoded + * size: the size of the data to be decoded + */ +typedef struct labcomm_mem_reader_context_t labcomm_mem_reader_context_t; +struct labcomm_mem_reader_context_t { + size_t size; + unsigned char *enc_data; +}; + +int labcomm_mem_reader( labcomm_reader_t *r, labcomm_reader_action_t action); + +#endif diff --git a/lib/c/labcomm_mem_writer.c b/lib/c/labcomm_mem_writer.c new file mode 100644 index 0000000000000000000000000000000000000000..7275649e2bf901ff24f47bff395e58b5a9226271 --- /dev/null +++ b/lib/c/labcomm_mem_writer.c @@ -0,0 +1,143 @@ +#include "labcomm_mem_writer.h" + +#include "stddef.h" // For size_t. +#include <errno.h> + +#include "labcomm.h" +#include "cppmacros.h" + +#define BUFFER_SIZE 150 // Suitable size is at least the size of a fully encoded message. Found by inspecting size of file genreated from the labcomm_fs_reader_writer.c on the same message type. + +// Put encdoded data directly in mcontext->mbuf or malloc new temporary memory. +// 1 == Allocate new memory. +// 2 == Use mcontext->buf directly. But _beware_; you can not then later change +// mcontext->buf to something else since the writer gets a reference to this +// buffer! +#if defined(MEM_WRITER_ENCODED_BUFFER) && (EMPTY(MEM_WRITER_ENCODED_BUFFER) != 1) + #define ENCODED_BUFFER MEM_WRITER_ENCODED_BUFFER +#else + #define ENCODED_BUFFER 1 +#endif + +static int get_writer_available(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext); +static void copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf); + +/* + * Write encoded messages to memory. w->context is assumed to be a pointer to a + * labcomm_mem_writer_context_t structure. + */ +int labcomm_mem_writer(labcomm_writer_t *w, labcomm_writer_action_t action) +{ + int result = 0; + // Unwrap pointers for easy access. + labcomm_mem_writer_context_t *mcontext = (labcomm_mem_writer_context_t *) w->context; + unsigned char *mbuf = mcontext->buf; + + switch (action) { + case labcomm_writer_alloc: { +#if (ENCODED_BUFFER == 1) + w->data = malloc(BUFFER_SIZE); // Buffer that LabComm will use for putting the encoded data. + if (w->data == NULL) { + result = -ENOMEM; + w->data_size = 0; + w->count = 0; + w->pos = 0; + } else { + w->data_size = BUFFER_SIZE; + w->count = BUFFER_SIZE; + w->pos = 0; + } +#elif (ENCODED_BUFFER == 2) + w->data = mbuf; + int bytes_left = (mcontext->length - mcontext->write_pos); + w->data_size = bytes_left; + w->count = bytes_left; + w->pos = mcontext->write_pos; +#endif + } break; + case labcomm_writer_free:{ +#if (ENCODED_BUFFER == 1) + free(w->data); +#endif + w->data = 0; + w->data_size = 0; + w->count = 0; + w->pos = 0; + } break; + case labcomm_writer_start:{ +#if (ENCODED_BUFFER == 1) + w->pos = 0; +#elif (ENCODED_BUFFER == 2) + w->pos = mcontext->write_pos; +#endif + } break; + case labcomm_writer_continue:{ // Encode-buffer(w->data) is full; empty/handle it. (w->pos == w->count) most likely. +#if (ENCODED_BUFFER == 1) + copy_data(w, mcontext, mbuf); + result = w->pos; // Assume result here should be number of bytes written. + w->pos = 0; +#elif (ENCODED_BUFFER == 2) + mcontext->write_pos = w->pos; +#endif + result = 0; + } break; + case labcomm_writer_end:{ // Nothing more to encode, handle encode-buffer(w->data). +#if (ENCODED_BUFFER == 1) + copy_data(w, mcontext, mbuf); + result = w->pos; + w->pos = 0; +#elif (ENCODED_BUFFER == 2) + mcontext->write_pos = w->pos; +#endif + result = 0; + } break; + case labcomm_writer_available:{ + result = w->count - w->pos; + } break; + } + return result; +} + +labcomm_mem_writer_context_t *labcomm_mem_writer_context_t_new(size_t init_pos, size_t length, unsigned char *buf) +{ + labcomm_mem_writer_context_t *mcontext = (labcomm_mem_writer_context_t *) malloc(sizeof(labcomm_mem_writer_context_t)); + if (mcontext == NULL) { + //fprintf(stderr, "error: Can not allocate labcomm_mem_writer_context_t.\n"); + } else { + mcontext->write_pos = init_pos; + mcontext->length = length; + mcontext->buf = buf; + } + return mcontext; +} + +void labcomm_mem_writer_context_t_free(labcomm_mem_writer_context_t **mcontext) +{ + free(*mcontext); + *mcontext = NULL; +} + +// Get the number of available bytes in the mcontext->buf buffer. +static int get_writer_available(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext) +{ + return (mcontext->length - mcontext->write_pos); +} + +// Copy data from encoded buffer to mbuf. +static void copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf) +{ + int writer_available = get_writer_available(w, mcontext); + if (( writer_available - w->pos) < 0) { + w->on_error(LABCOMM_ERROR_ENC_BUF_FULL, 3, "labcomm_writer_t->pos=%i, but available in mcontext is %i", w->pos, writer_available); + } else { + int i; + for (i = 0; i < w->pos; ++i, mcontext->write_pos++) { + mbuf[mcontext->write_pos] = w->data[i]; + } + } +} + +void test_copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf) +{ + copy_data(w, mcontext, mbuf); +} diff --git a/lib/c/labcomm_mem_writer.h b/lib/c/labcomm_mem_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..4585903c93beea5ae17bd2a845c216b801a59539 --- /dev/null +++ b/lib/c/labcomm_mem_writer.h @@ -0,0 +1,25 @@ +#ifndef LABCOMM_MEM_WRITER_H +#define LABCOMM_MEM_WRITER_H + +#include "labcomm.h" + +/* Wrapper structure for the memory buffer including a writer position. */ +typedef struct labcomm_mem_writer_context_t labcomm_mem_writer_context_t; +struct labcomm_mem_writer_context_t { + size_t write_pos; // Position where next write should be. + size_t length; // Length of the buffer. + unsigned char *buf; // Allocated destination buffer. +}; + +int labcomm_mem_writer(labcomm_writer_t *w, labcomm_writer_action_t action); + +/* Wrapper the internal static function copy_data. This is needed so that the exceptions can be unit tested. */ +void test_copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf); + +/* Allocate new labcomm_mem_writer_context_t. */ +labcomm_mem_writer_context_t *labcomm_mem_writer_context_t_new(size_t init_pos, size_t length, unsigned char *buf); + +/* Deallocate mcontext. */ +void labcomm_mem_writer_context_t_free(labcomm_mem_writer_context_t **mcontext); + +#endif diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h index 20d3fe875c1ea636eeef87e27dcc8d0ad3a4c335..57239ff07134227aa24b5b09f6430e118cf4f0f7 100644 --- a/lib/c/labcomm_private.h +++ b/lib/c/labcomm_private.h @@ -1,8 +1,17 @@ #ifndef _LABCOMM_PRIVATE_H_ #define _LABCOMM_PRIVATE_H_ -#include <endian.h> -#include <stdio.h> +#ifdef ARM_CORTEXM3_CODESOURCERY + #include <machine/endian.h> +#else + #include <endian.h> +#endif + +// Some projects can not use stdio.h. +#ifndef LABCOMM_NO_STDIO + #include <stdio.h> +#endif + #include <stdlib.h> #include <string.h> #include "labcomm.h" @@ -51,6 +60,8 @@ typedef struct labcomm_decoder { labcomm_handler_typecast_t, void *context); int (*do_decode_one)(struct labcomm_decoder *decoder); + labcomm_error_handler_callback on_error; + labcomm_handle_new_datatype_callback on_new_datatype; } labcomm_decoder_t; /* @@ -209,6 +220,7 @@ typedef struct labcomm_encoder { void (*do_encode)(struct labcomm_encoder *encoder, labcomm_signature_t *signature, void *value); + labcomm_error_handler_callback on_error; } labcomm_encoder_t; void labcomm_internal_encoder_register( @@ -231,7 +243,7 @@ void labcomm_internal_encoder_user_action(struct labcomm_encoder *encoder, static inline void labcomm_write_##name(labcomm_writer_t *w, type data) { \ int i; \ for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ - if (w->pos >= w->count) { \ + if (w->pos >= w->count) { /*buffer is full*/ \ w->write(w, labcomm_writer_continue); \ } \ w->data[w->pos] = ((unsigned char*)(&data))[i]; \ diff --git a/lib/c/test/test_labcomm.c b/lib/c/test/test_labcomm.c new file mode 100644 index 0000000000000000000000000000000000000000..fc4004c109e5583ae2acfbbe00caa33f07f93036 --- /dev/null +++ b/lib/c/test/test_labcomm.c @@ -0,0 +1,187 @@ + +#include "CUnit/Basic.h" +#include "CUnit/Console.h" +#include <stdbool.h> + +#include <labcomm.h> +#include <labcomm_mem_writer.h> +#include <labcomm_mem_reader.h> +#include "test/testdata/gen/test_sample.h" + +#define TEST_BUFFER_SIZE (50) + +void test_error_handler(enum labcomm_error error_id, size_t nbr_va_args, ...); + +int init_suit_labcomm() +{ + return 0; +} + +int clean_suit_labcomm() +{ + return 0; +} + +void setup_connected_encoder_decoder(struct labcomm_encoder **enc, + labcomm_mem_writer_context_t *enc_ctx, + struct labcomm_decoder **dec, + labcomm_mem_reader_context_t *dec_ctx) +{ + enc_ctx->write_pos = 0; + enc_ctx->buf = malloc(TEST_BUFFER_SIZE); + enc_ctx->length = TEST_BUFFER_SIZE; + + *enc = labcomm_encoder_new(labcomm_mem_writer, enc_ctx); + + dec_ctx->size = 0; + dec_ctx->enc_data = enc_ctx->buf; + *dec = labcomm_decoder_new(labcomm_mem_reader, dec_ctx); + + labcomm_register_error_handler_decoder(*dec, test_error_handler); + labcomm_register_error_handler_encoder(*enc, test_error_handler); +} + +static bool in_error = false; +static enum labcomm_error in_error_id = LABCOMM_ERROR_ENUM_BEGIN_GUARD; +void test_error_handler(enum labcomm_error error_id, size_t nbr_va_args, ...) +{ + in_error = true; + in_error_id = error_id; +} + +static bool got_sample = false; +void test_decoder_handle_test_sample_test_var(test_sample_test_var *v, void *ctx) +{ + got_sample = true; +} + +void test_decoder_decode_sig() +{ + labcomm_mem_writer_context_t enc_ctx; + struct labcomm_encoder *encoder; + labcomm_mem_reader_context_t dec_ctx; + struct labcomm_decoder *decoder; + setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx); + + labcomm_encoder_register_test_sample_test_var(encoder); + dec_ctx.size = enc_ctx.write_pos; + + labcomm_decoder_register_test_sample_test_var(decoder, + test_decoder_handle_test_sample_test_var, NULL); + labcomm_decoder_decode_one(decoder); + + CU_ASSERT_FALSE(in_error); + enc_ctx.write_pos = 0; + test_sample_test_var var = 1; + labcomm_encode_test_sample_test_var(encoder, &var); + dec_ctx.size = enc_ctx.write_pos; + labcomm_decoder_decode_one(decoder); + + CU_ASSERT_FALSE(in_error); + CU_ASSERT_FALSE(got_sample); + + labcomm_decoder_free(decoder); + labcomm_encoder_free(encoder); + free(enc_ctx.buf); + + in_error = false; + in_error_id = LABCOMM_ERROR_ENUM_BEGIN_GUARD; + got_sample = false; +} + +static bool got_new_datatype = false; +static labcomm_signature_t new_sig; +int test_new_datatype(struct labcomm_decoder *decoder, + labcomm_signature_t *sig) +{ + got_new_datatype = true; + memcpy(&new_sig, sig, sizeof(labcomm_signature_t)); + return 0; +} + +void test_decode_unreg_signature_handle() +{ + labcomm_mem_writer_context_t enc_ctx; + struct labcomm_encoder *encoder; + labcomm_mem_reader_context_t dec_ctx; + struct labcomm_decoder *decoder; + setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx); + + labcomm_encoder_register_test_sample_test_var(encoder); + dec_ctx.size = enc_ctx.write_pos; + labcomm_decoder_register_new_datatype_handler(decoder, test_new_datatype); + labcomm_decoder_decode_one(decoder); + + CU_ASSERT_TRUE(got_new_datatype); + CU_ASSERT_EQUAL( + memcmp(new_sig.signature, dec_ctx.enc_data, dec_ctx.size), 0); + + got_new_datatype = false; + labcomm_decoder_free(decoder); + labcomm_encoder_free(encoder); + free(enc_ctx.buf); +} + +void test_decode_unreg_signature_error() +{ + labcomm_mem_writer_context_t enc_ctx; + struct labcomm_encoder *encoder; + labcomm_mem_reader_context_t dec_ctx; + struct labcomm_decoder *decoder; + setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx); + + labcomm_encoder_register_test_sample_test_var(encoder); + dec_ctx.size = enc_ctx.write_pos; + + labcomm_decoder_decode_one(decoder); + + CU_ASSERT_TRUE(in_error); + CU_ASSERT_EQUAL(in_error_id, LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE); + got_new_datatype = false; + labcomm_decoder_free(decoder); + labcomm_encoder_free(encoder); + free(enc_ctx.buf); +} +int main() +{ + CU_pSuite suite_decoder = NULL; + + // Initialize CUnit test registry. + if (CUE_SUCCESS != CU_initialize_registry()) { + return CU_get_error(); + } + + // Add our test suites. + suite_decoder = CU_add_suite("transport_enc_dec", + init_suit_labcomm, clean_suit_labcomm); + if (suite_decoder == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + (CU_add_test(suite_decoder, "test_decoder_decode_sig", + test_decoder_decode_sig) == NULL) + || + (CU_add_test(suite_decoder, "test_decode_unreg_signature_handle", + test_decode_unreg_signature_handle) == NULL) + || + (CU_add_test(suite_decoder, "test_decode_unreg_signature_error", + test_decode_unreg_signature_error) == NULL) + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + // Set verbosity. + CU_basic_set_mode(CU_BRM_VERBOSE); + /*CU_console_run_tests();*/ + + // Run all test suites. + CU_basic_run_tests(); + + // Clean up. + CU_cleanup_registry(); + + return CU_get_error(); +} diff --git a/lib/c/test/test_labcomm_errors b/lib/c/test/test_labcomm_errors new file mode 100755 index 0000000000000000000000000000000000000000..d55cfeb49cd8a2c1941d63bed9b2d276d5d2d4aa Binary files /dev/null and b/lib/c/test/test_labcomm_errors differ diff --git a/lib/c/test/test_labcomm_errors.c b/lib/c/test/test_labcomm_errors.c new file mode 100644 index 0000000000000000000000000000000000000000..7742175f4d30da7c593f0b8a41f0f1e13b153dac --- /dev/null +++ b/lib/c/test/test_labcomm_errors.c @@ -0,0 +1,168 @@ +#include "test_labcomm_errors.h" + +#include <stdlib.h> + +#include <labcomm.h> +#include <labcomm_private.h> +#include <labcomm_mem_writer.h> +#include <labcomm_mem_reader.h> + +static enum labcomm_error callback_error_id; + +int assert_callback(enum labcomm_error expected, const char *name, const char *err_msg) +{ + int success; + printf("----> %s()\n", name); + if (callback_error_id == expected) { + printf("Succeeded.\n"); + success = 1; + } else { + printf("Failed! %s\n", err_msg); + success = 0; + } + return success; +} + +/* Our callback that just logs which error_id that the library reported. */ +void test_callback(enum labcomm_error error_id, size_t nbr_va_args, ...) +{ + va_list arg_pointer; + va_start(arg_pointer, nbr_va_args); + va_end(arg_pointer); + callback_error_id = error_id; +} + +void reset_callback_erro_id() +{ + callback_error_id = -128; +} + +int encoded_size_mock(void *voidp) +{ + return 0; +} + +int test_enc_not_reg_encoder_sign() +{ + reset_callback_erro_id(); + unsigned char *buf = (unsigned char *) "a"; + labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf); + labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext); + labcomm_register_error_handler_encoder(encoder, test_callback); + + labcomm_signature_t signature = {.type = 0, .name = "test_signature", .encoded_size = encoded_size_mock, .size = 0, .signature = (unsigned char *) "0"}; + encoder->do_encode(encoder, &signature, NULL); + + return assert_callback(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, __FUNCTION__, ""); +} + +int test_enc_missing_do_reg() +{ + reset_callback_erro_id(); + unsigned char *buf = (unsigned char *) "a"; + labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf); + labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext); + labcomm_register_error_handler_encoder(encoder, test_callback); + + encoder->do_register = NULL; + labcomm_internal_encoder_register(encoder, NULL, NULL); + + return assert_callback(LABCOMM_ERROR_ENC_MISSING_DO_REG, __FUNCTION__, ""); +} + +int test_enc_missing_do_encode() +{ + reset_callback_erro_id(); + unsigned char *buf = (unsigned char *) "a"; + labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf); + labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext); + labcomm_register_error_handler_encoder(encoder, test_callback); + + encoder->do_encode = NULL; + labcomm_internal_encode(encoder, NULL, NULL); + + return assert_callback(LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, __FUNCTION__, ""); +} + +int test_enc_buf_full() +{ + reset_callback_erro_id(); + unsigned char *buf = (unsigned char *) "a"; + labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf); + labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext); + labcomm_register_error_handler_encoder(encoder, test_callback); + + unsigned char *mbuf = mcontext->buf; + labcomm_writer_t writer = encoder->writer; + writer.data = malloc(1); + writer.pos = 1; + mcontext->write_pos = 1; + test_copy_data(&writer, mcontext, mbuf); + + return assert_callback(LABCOMM_ERROR_ENC_BUF_FULL, __FUNCTION__, ""); +} + +void labcomm_decoder_typecast_t_mock(struct labcomm_decoder *decoder, labcomm_handler_typecast_t handler, void *voidp) +{ + ; +} + +void labcomm_handler_typecast_t_mock(void *arg1, void *arg2) +{ + ; +} + +int test_dec_missing_do_reg() +{ + reset_callback_erro_id(); + unsigned char *buf = (unsigned char *) "a"; + labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) malloc(sizeof(labcomm_mem_reader_context_t)); + labcomm_decoder_t *decoder = labcomm_decoder_new(labcomm_mem_reader, mcontext); + labcomm_register_error_handler_decoder(decoder, test_callback); + + decoder->do_register = NULL; + labcomm_internal_decoder_register(decoder, NULL, labcomm_decoder_typecast_t_mock, labcomm_handler_typecast_t_mock, buf); + + return assert_callback(LABCOMM_ERROR_DEC_MISSING_DO_REG, __FUNCTION__, ""); +} + +int test_dec_missing_do_decode_one() +{ + reset_callback_erro_id(); + labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) malloc(sizeof(labcomm_mem_reader_context_t)); + labcomm_decoder_t *decoder = labcomm_decoder_new(labcomm_mem_reader, mcontext); + labcomm_register_error_handler_decoder(decoder, test_callback); + + decoder->do_decode_one = NULL; + labcomm_decoder_decode_one(decoder); + + return assert_callback(LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE, __FUNCTION__, ""); +} + +int main() +{ + printf("####> Begin tests.\n"); + size_t nbr_succeed = 0; + size_t nbr_tests = 6; // Increment this when new tests are written. + nbr_succeed += test_enc_not_reg_encoder_sign(); + nbr_succeed += test_enc_missing_do_reg(); + nbr_succeed += test_enc_missing_do_encode(); + nbr_succeed += test_enc_buf_full(); + nbr_succeed += test_dec_missing_do_reg(); + nbr_succeed += test_dec_missing_do_decode_one(); + + // Too tedius to test really... + //nbr_succeed += test_dec_unknown_datatype(); + //nbr_succeed += test_dec_index_mismatch(); + //nbr_succeed += test_dec_type_not_found(); + + //nbr_succeed += test_unimplemented_func(); // This test will be obsolete in the future ;-) + //nbr_succeed += test_user_def(); // There are no user defined errors in the library of course. + + printf("####> End tests.\nSummary: %i/%i tests succeed.\n", nbr_succeed, nbr_tests); + if (nbr_succeed == nbr_tests) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} diff --git a/lib/c/test/test_labcomm_errors.h b/lib/c/test/test_labcomm_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..8cc39182950f981e3955537da46780f9263256a9 --- /dev/null +++ b/lib/c/test/test_labcomm_errors.h @@ -0,0 +1,6 @@ +#ifndef TEST_LABCOMM_ERRORS_H +#define TEST_LABCOMM_ERRORS_H + +void test_not_reg_encoder_sign(); + +#endif diff --git a/lib/c/test/testdata/test_sample.lc b/lib/c/test/testdata/test_sample.lc new file mode 100644 index 0000000000000000000000000000000000000000..bf686a731f5c075a55d6a97dd632b6c1499bc000 --- /dev/null +++ b/lib/c/test/testdata/test_sample.lc @@ -0,0 +1 @@ +sample int test_var;