diff --git a/src/Makefile b/src/Makefile
index 367a786d..d489d122 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -218,6 +218,7 @@ endif
     # Where the SDL frameworks are located
     FWDIR = /Library/Frameworks
     BIN = ../bin/grafx2-$(API)
+    TESTSBIN = ../bin/tests-$(API)
     PKG_CONFIG_PATH ?= $(shell if [ -d ../3rdparty/usr/lib/pkgconfig ] ; then echo "$${PWD}/../3rdparty/usr/lib/pkgconfig" ; fi )
 ifneq ($(PKG_CONFIG_PATH), )
     PKG_CONFIG := PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG)
@@ -643,6 +644,7 @@ endif
 
         # Compiles a regular linux executable for the native platform
         BIN = ../bin/grafx2-$(API)
+        TESTSBIN = ../bin/tests-$(API)
         COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -g
         ifeq ($(API),sdl)
           COPT += $(shell sdl-config --cflags)
@@ -794,7 +796,8 @@ endif
 
 ### And now for the real build rules ###
 
-.PHONY : all debug release clean depend force install uninstall valgrind doc doxygen htmldoc
+.PHONY : all debug release clean depend force install uninstall valgrind \
+         doc doxygen htmldoc check
 
 # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically.
 OBJS = main.o init.o graph.o $(APIOBJ) misc.o special.o \
@@ -813,8 +816,19 @@ OBJS = main.o init.o graph.o $(APIOBJ) misc.o special.o \
 ifndef NORECOIL
 OBJS += loadrecoil.o recoil.o
 endif
+
+TESTSOBJS = $(patsubst %.c,%.o,$(wildcard tests/*.c)) \
+            miscfileformats.o oldies.o libraw2crtc.o \
+			loadsavefuncs.o \
+			unicode.o \
+            io.o realpath.o version.o pversion.o \
+			gfx2surface.o \
+            gfx2log.o gfx2mem.o
+
 OBJ = $(addprefix $(OBJDIR)/,$(OBJS))
-DEP = $(patsubst %.o,%.d,$(OBJ))
+TESTSOBJ = $(addprefix $(OBJDIR)/,$(TESTSOBJS))
+
+DEP = $(patsubst %.o,%.d,$(OBJ) $(TESTSOBJ))
 
 GENERATEDOCOBJ = $(addprefix $(OBJDIR)/,generatedoc.o hotkeys.o keyboard.o)
 
@@ -997,6 +1011,9 @@ ifeq ($(SWITCH), 1)
 		@echo built ... $(BIN).nro
 endif
 
+check:	$(TESTSBIN)
+	$(TESTSBIN)
+
 # .tgz archive with source only files
 SRCARCH = ../src-$(VERSIONTAG).tgz
 
@@ -1104,13 +1121,18 @@ endif
 
 $(BIN) : $(OBJ)
 	@test -d ../bin || $(MKDIR) ../bin
-	$(CC) $(OBJ) -o $(BIN) $(LOPT) $(LDFLAGS) $(LDLIBS)
+	$(CC) $(OBJ) -o $@ $(LOPT) $(LDFLAGS) $(LDLIBS)
 ifeq ($(PLATFORM),Haiku)
 	rc -o $(OBJDIR)/grafx2.rsrc grafx2.rdef
 	xres -o $(BIN) $(OBJDIR)/grafx2.rsrc
 	mimeset -f $(BIN)
 endif
 
+$(TESTSBIN):	$(TESTSOBJ)
+	@test -d ../bin || $(MKDIR) ../bin
+	$(CC) $(TESTSOBJ) -o $@ $(LOPT) $(LDFLAGS) $(LDLIBS)
+
+
 $(GENERATEDOCBIN): $(GENERATEDOCOBJ)
 	@test -d ../bin || $(MKDIR) ../bin
 	$(CC) $(GENERATEDOCOBJ) -o $(GENERATEDOCBIN) $(LOPT) $(LDFLAGS)
@@ -1140,17 +1162,17 @@ endif
 $(OBJ):	$(CFLAGS_CACHE)
 
 $(OBJDIR)/%.o : %.c
-	$(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR))
+	@$(MKDIR) -p $(@D)
 	$(CC) $(COPT) $(CFLAGS) -c $*.c -o $(OBJDIR)/$*.o
 
 $(OBJDIR)/%.o : %.m
-	$(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR))
+	@$(MKDIR) -p $(@D)
 	$(CC) $(COPT) -c $*.m -o $(OBJDIR)/$*.o
 
 depend:	$(DEP)
 
 $(OBJDIR)/%.d :	%.c
-	$(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR))
+	@$(MKDIR) -p $(@D)
 	$(CC) $(COPT) $(CFLAGS) $(DEPFLAGS) -o $@ $<
 
 # update the gfx2.rc Windows ressource file
@@ -1171,7 +1193,8 @@ $(OBJDIR)/haiku.o : haiku.cpp
 
 clean :
 	$(DELCOMMAND) $(OBJ) $(DEP)
-	$(DELCOMMAND) $(BIN)
+	$(DELCOMMAND) $(TESTSOBJ)
+	$(DELCOMMAND) $(BIN) $(TESTSBIN)
 	if [ -d ../3rdparty ] ; then $(DELCOMMAND) recoil.c recoil.h ; fi
 
 ifneq ($(PLATFORM),amiga-vbcc)
diff --git a/src/miscfileformats.c b/src/miscfileformats.c
index 9d54a217..372a5ceb 100644
--- a/src/miscfileformats.c
+++ b/src/miscfileformats.c
@@ -6307,7 +6307,7 @@ void Load_MOTO(T_IO_Context * context)
  * - cc xx          : encodes a "repeat run" (cc > 0 : count)
  */
 //#define MOTO_MAP_NOPACKING
-static unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned int unpacked_len)
+unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned int unpacked_len)
 {
   unsigned int src;
   unsigned int dst = 0;
diff --git a/src/tests/mockloadsave.c b/src/tests/mockloadsave.c
new file mode 100644
index 00000000..a2f28db3
--- /dev/null
+++ b/src/tests/mockloadsave.c
@@ -0,0 +1,59 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2019      Thomas Bernard
+    Copyright 2007-2018 Adrien Destugues
+    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+    Grafx2 is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    as published by the Free Software Foundation; version 2
+    of the License.
+
+    Grafx2 is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Grafx2; if not, see 
+
+*/
+
+#include 
+#include "../loadsave.h"
+
+void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte bpp)
+{
+  printf("Pre_load()\n");
+}
+
+byte Get_pixel(T_IO_Context *context, short x, short y)
+{
+  return 0;
+}
+
+void Pixel_in_layer(int layer, word x, word y, byte color)
+{
+}
+
+void Set_pixel(T_IO_Context *context, short x, short y, byte c)
+{
+}
+
+void Set_saving_layer(T_IO_Context *context, int layer)
+{
+}
+
+void Set_loading_layer(T_IO_Context *context, int layer)
+{
+}
+
+void Set_image_mode(T_IO_Context *context, enum IMAGE_MODES mode)
+{
+}
+
+void Set_frame_duration(T_IO_Context *context, int duration)
+{
+}
diff --git a/src/tests/mockui.c b/src/tests/mockui.c
new file mode 100644
index 00000000..9d07be46
--- /dev/null
+++ b/src/tests/mockui.c
@@ -0,0 +1,125 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2019      Thomas Bernard
+    Copyright 2007-2018 Adrien Destugues
+    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+    Grafx2 is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    as published by the Free Software Foundation; version 2
+    of the License.
+
+    Grafx2 is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Grafx2; if not, see 
+
+*/
+
+#include 
+#include 
+#include "../struct.h"
+
+void Warning_message(const char * message)
+{
+  puts(message);
+}
+
+void Warning_with_format(const char *template, ...)
+{
+  va_list arg_ptr;
+
+  va_start(arg_ptr, template);
+  vprintf(template, arg_ptr);
+  va_end(arg_ptr);
+}
+
+void Error_function(int error_code, const char *filename, int line_number, const char *function_name)
+{
+  printf("%s:%d %s(): Error %d\n", filename, line_number, function_name, error_code);
+}
+
+void Warning_function(const char *message, const char *filename, int line_number, const char *function_name)
+{
+  printf("%s:%d %s(): Warning: %s\n", filename, line_number, function_name, message);
+}
+
+void Window_help(int section, const char * sub_section)
+{
+  printf("Window_help(%d, %s)\n", section, sub_section);
+}
+
+void Open_window(word width, word height, const char * title)
+{
+  printf("Open_window() %hux%hu : %s\n", width, height, title);
+}
+
+void Close_window()
+{
+}
+
+void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color)
+{
+}
+
+void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label)
+{
+  printf("Window_dropdown_add_item(%p, %hu, %s)\n", dropdown, btn_number, label);
+}
+
+void Window_dropdown_clear_items(T_Dropdown_button * dropdown)
+{
+}
+
+T_Dropdown_button * Window_set_dropdown_button(word x_pos, word y_pos,
+  word width, word height, word dropdown_width, const char *label,
+  byte display_choice, byte display_centered, byte display_arrow,
+  byte active_button,byte bottom_up)
+{
+  return NULL;
+}
+
+T_Normal_button * Window_set_normal_button(word x_pos, word y_pos,
+  word width, word height, const char * title, byte undersc_letter,
+  byte clickable, word shortcut)
+{
+  return NULL;
+}
+
+short Window_clicked_button(void)
+{
+  return 0;
+}
+
+int Is_shortcut(word key, word function)
+{
+  printf("Is_shortcut(%04x, %04x)\n", key, function);
+  return 0;
+}
+
+void Update_rect(short x, short y, unsigned short width, unsigned short height)
+{
+}
+
+void Display_cursor(void)
+{
+}
+
+void Hide_cursor(void)
+{
+}
+
+word Count_used_colors(dword * usage)
+{
+  return 256;
+}
+
+word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height)
+{
+  return 256;
+}
diff --git a/src/tests/testlist.h b/src/tests/testlist.h
new file mode 100644
index 00000000..6f537b49
--- /dev/null
+++ b/src/tests/testlist.h
@@ -0,0 +1,5 @@
+/* list of tests
+ * TEST(function_to_test) */
+
+TEST(MOTO_MAP_pack)
+
diff --git a/src/tests/testmain.c b/src/tests/testmain.c
new file mode 100644
index 00000000..05b16f5d
--- /dev/null
+++ b/src/tests/testmain.c
@@ -0,0 +1,127 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2018-2019 Thomas Bernard
+    Copyright 2011 Pawel Góralski
+    Copyright 2009 Petter Lindquist
+    Copyright 2008 Yves Rizoud
+    Copyright 2008 Franck Charlet
+    Copyright 2007-2011 Adrien Destugues
+    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+    Grafx2 is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    as published by the Free Software Foundation; version 2
+    of the License.
+
+    Grafx2 is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Grafx2; if not, see 
+*/
+///@file testmain.c
+/// Unit tests.
+
+#include 
+#include 
+#include "../struct.h"
+#include "../global.h"
+#include "../gfx2log.h"
+#include "tests.h"
+
+#ifdef ENABLE_FILENAMES_ICONV
+iconv_t cd;             // FROMCODE => TOCODE
+iconv_t cd_inv;         // TOCODE => FROMCODE
+iconv_t cd_utf16;       // FROMCODE => UTF16
+iconv_t cd_utf16_inv;   // UTF16 => FROMCODE
+#endif
+signed char File_error;
+
+T_Config Config;
+
+T_Document Main;
+T_Document Spare;
+byte * Screen_backup;
+byte * Main_Screen;
+short Screen_width;
+short Screen_height;
+short Original_screen_X;
+short Original_screen_Y;
+
+byte Menu_factor_X;
+byte Menu_factor_Y;
+int Pixel_ratio;
+
+byte First_color_in_palette;
+byte Back_color;
+byte MC_Dark;
+byte MC_Light;
+
+T_Window Window_stack[8];
+byte Windows_open;
+
+dword Key;
+
+static const struct {
+  int (*test_func)(void);
+  const char * test_name;
+} tests[] = {
+#define TEST(func) { Test_ ## func, # func },
+#include "testlist.h"
+#undef TEST
+  { NULL, NULL}
+};
+
+void init(void)
+{
+#ifdef ENABLE_FILENAMES_ICONV
+  // iconv is used to convert filenames
+  cd = iconv_open(TOCODE, FROMCODE);  // From UTF8 to ANSI
+  cd_inv = iconv_open(FROMCODE, TOCODE);  // From ANSI to UTF8
+#if (defined(SDL_BYTEORDER) && (SDL_BYTEORDER == SDL_BIG_ENDIAN)) || (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))
+  cd_utf16 = iconv_open("UTF-16BE", FROMCODE); // From UTF8 to UTF16
+  cd_utf16_inv = iconv_open(FROMCODE, "UTF-16BE"); // From UTF16 to UTF8
+#else
+  cd_utf16 = iconv_open("UTF-16LE", FROMCODE); // From UTF8 to UTF16
+  cd_utf16_inv = iconv_open(FROMCODE, "UTF-16LE"); // From UTF16 to UTF8
+#endif
+#endif /* ENABLE_FILENAMES_ICONV */
+}
+
+/**
+ * Test program entry point
+ */
+int main(int argc, char * * argv)
+{
+  int i, r;
+  int fail = 0;
+
+  GFX2_verbosity_level = GFX2_DEBUG;
+
+  for (i = 0; tests[i].test_func != 0; i++)
+  {
+    printf("Testing %s :\n", tests[i].test_name);
+    r = tests[i].test_func();
+    if (r)
+      printf("OK\n");
+    else {
+      printf("FAILED\n");
+      fail++;
+    }
+  }
+
+  if (fail == 0)
+  {
+    printf("All tests succesfull\n");
+    return 0;
+  }
+  else
+  {
+    printf("%d tests failed\n", fail);
+    return 1;
+  }
+}
diff --git a/src/tests/tests.c b/src/tests/tests.c
index 78d8fa79..008db0c9 100644
--- a/src/tests/tests.c
+++ b/src/tests/tests.c
@@ -28,6 +28,11 @@
 ///
 /// TODO : make a test binary and include the tests to the constant-integration
 
+#include 
+#include 
+#include "../struct.h"
+#include "../gfx2log.h"
+
 /**
  * Tests for MOTO_MAP_pack()
  */
diff --git a/src/tests/tests.h b/src/tests/tests.h
new file mode 100644
index 00000000..79ff97c9
--- /dev/null
+++ b/src/tests/tests.h
@@ -0,0 +1,29 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2019 Thomas Bernard
+    Copyright 2007-2011 Adrien Destugues
+    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+    Grafx2 is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    as published by the Free Software Foundation; version 2
+    of the License.
+
+    Grafx2 is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Grafx2; if not, see 
+*/
+#ifndef TESTS_H_INCLUDED
+#define TESTS_H_INCLUDED
+
+#define TEST(func) int Test_ ## func (void);
+#include "testlist.h"
+#undef TEST
+
+#endif