diff --git a/.gitattributes b/.gitattributes
index 78a473397e1f58fa87b195f956117fa9486736fb..83ffa0f7aaeee92a316e7f721c1b3602f5b06226 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -180,7 +180,6 @@ testfont binary
 /src/modules/Image/pattern.c foreign_ident
 /src/modules/Image/pnm.c foreign_ident
 /src/modules/Image/polyfill.c foreign_ident
-/src/modules/Image/testsuite.in foreign_ident
 /src/modules/Image/togif.c foreign_ident
 /src/modules/Image/x.c foreign_ident
 /src/modules/MIME/Makefile.in foreign_ident
diff --git a/src/modules/Image/Makefile b/src/modules/Image/Makefile
index 2e819f632d6605a3fbe1cab51fa2b83105d9eb58..f851b5e6845a3405931ff5697620007eafa2634c 100644
--- a/src/modules/Image/Makefile
+++ b/src/modules/Image/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 1998/04/16 00:38:52 mirar Exp $
+# $Id: Makefile,v 1.10 1998/04/16 04:33:13 mirar Exp $
 
 DOCFILES = doc-header \
    image.c \
@@ -50,3 +50,11 @@ $(WMMLDOCPLACE): $(DOCFILES) mkwmml.pike Makefile
 
 wmml:	$(WMMLDOCPLACE)
 
+testsuite.in: testsuite.in.in mktests.pike
+	pike mktests.pike -t testsuite.in.in >testsuite.in
+
+tests.pike: testsuite.in.in mktests.pike
+	pike mktests.pike testsuite.in.in >tests.pike
+
+test:	tests.pike
+	pike tests.pike
diff --git a/src/modules/Image/mktests.pike b/src/modules/Image/mktests.pike
index 16d0fe6407ec6d5854713dbda98a37de9e27c3c0..2fbc83f83768e279147ebb8d512b0c315218729a 100644
--- a/src/modules/Image/mktests.pike
+++ b/src/modules/Image/mktests.pike
@@ -4,27 +4,41 @@ array modules=({});
 array chapters=({});
 array tests=({});
 
+int mode=0;
+
 void finish_test()
 {
    if (!name) return;
    int m1,m2,m3;
-   write("void test_"+(m1=sizeof(modules))+
-	 "_"+(m2=sizeof(chapters))+
-	 "_"+(m3=sizeof(tests))+"()\n"
-	 "{\n"
-	 "   write(\"  test: "+name+"...\");\n"
-	 "   mixed err=catch {\n"+
-	 test+
-	 "   };\n"
-	 "   if (stringp(err))\n"
-	 "      write(err+\"\\n\");\n"
-	 "   else\n"
-	 "   {\n"
-	 "      failed++;\n"
-	 "      err=({err[0],err[1][sizeof(err[1])-2..]});\n"
-	 "      write(\"\\n\"+master()->describe_backtrace(err));\n"
-	 "   }\n"
-	 "}\n\n");
+
+   switch (mode)
+   {
+      case 0:
+	 write("void test_"+(m1=sizeof(modules))+
+	       "_"+(m2=sizeof(chapters))+
+	       "_"+(m3=sizeof(tests))+"()\n"
+	       "{\n"
+	       "   write(\"  test: "+name+"...\");\n"
+	       "   mixed err=catch {\n"+
+	       test+
+	       "   };\n"
+	       "   if (stringp(err))\n"
+	       "      write(err+\"\\n\");\n"
+	       "   else\n"
+	       "   {\n"
+	       "      failed++;\n"
+	       "      err=({err[0],err[1][sizeof(err[1])-2..]});\n"
+	       "      write(\"\\n\"+master()->describe_backtrace(err));\n"
+	       "   }\n"
+	       "}\n\n");
+	 break;
+      case 1:
+	 test=cpp("#define ok(S) return \"ok\"\n"
+		  "#define fail(S) return (S)\n"+
+		  replace(test,"ok()","ok(\"ok\")"));
+	 write("test_any([["+test+"]], \"ok\")\n");
+	 break;
+   }
    name=0;
 }
 
@@ -43,16 +57,19 @@ void finish_chapter()
    if (!chapter) return;
    finish_test();
    int m1,m2;
-   write("void test_chapter_"+(m1=sizeof(modules))
-	 +"_"+(m2=sizeof(chapters))+"()\n"
-	 "{\n"
-	 "   int infailed=failed,inisok=isok;\n"
-	 "   write(\" chapter: "+chapter+"\\n\");\n");
-   foreach (indices(tests),int n)
-      write("   test_"+m1+"_"+m2+"_"+(n+1)+"();\n");
-   write("   write(\" tests failed: \"+(failed-infailed)+\"\\n\"\n"
-	 "         \" tests ok:     \"+(isok-inisok)+\"\\n\");\n");
-   write("}\n\n");
+   if (!mode)
+   {
+      write("void test_chapter_"+(m1=sizeof(modules))
+	    +"_"+(m2=sizeof(chapters))+"()\n"
+	    "{\n"
+	    "   int infailed=failed,inisok=isok;\n"
+	    "   write(\" chapter: "+chapter+"\\n\");\n");
+      foreach (indices(tests),int n)
+	 write("   test_"+m1+"_"+m2+"_"+(n+1)+"();\n");
+      write("   write(\" tests failed: \"+(failed-infailed)+\"\\n\"\n"
+	    "         \" tests ok:     \"+(isok-inisok)+\"\\n\");\n");
+      write("}\n\n");
+   }
    tests=({});
    werror(" generating chapter: "+chapter+"\n");
 }
@@ -69,15 +86,18 @@ void finish_module()
    if (!module) return;
    finish_chapter();
    int m;
-   write("void test_module_"+(m=sizeof(modules))+"()\n"
-	 "{\n"
-	 "   int infailed=failed,inisok=isok;\n"
-	 "   write(\"module: "+module+"\\n\");\n");
-   foreach (indices(chapters),int n)
-      write("   test_chapter_"+m+"_"+(n+1)+"();\n");
-   write("   write(\"tests failed: \"+(failed-infailed)+\"\\n\"\n"
-	 "         \"tests ok:     \"+(isok-inisok)+\"\\n\");\n");
-   write("}\n\n");
+   if (!mode)
+   {
+      write("void test_module_"+(m=sizeof(modules))+"()\n"
+	    "{\n"
+	    "   int infailed=failed,inisok=isok;\n"
+	    "   write(\"module: "+module+"\\n\");\n");
+      foreach (indices(chapters),int n)
+	 write("   test_chapter_"+m+"_"+(n+1)+"();\n");
+      write("   write(\"tests failed: \"+(failed-infailed)+\"\\n\"\n"
+	    "         \"tests ok:     \"+(isok-inisok)+\"\\n\");\n");
+      write("}\n\n");
+   }
    chapters=({});
 }
 
@@ -90,12 +110,13 @@ void new_module(string name,string file,int line)
 
 int main(int ac,array am)
 {
-   int mode=0;
    int n;
 
+   if (ac>=2 && am[1]=="-t") mode=1,am=am[..0]+am[2..];
+
    if (ac<2) 
    {
-      werror("usage: mktests <file>\n");
+      werror("usage: mktests [-t] <file>\n");
       return 1;
    }
 
@@ -140,7 +161,7 @@ int main(int ac,array am)
 	 write("   test_module_"+(n+1)+"();\n");
       write("   write(\"total tests failed: \"+failed+\"\\n\"\n"
 	    "         \"total tests ok:     \"+isok+\"\\n\");\n"
-	    "   return !failed;\n"
+	    "   return !!failed;\n"
 	    "}\n\n");
    }
 }
diff --git a/src/modules/Image/testsuite.in b/src/modules/Image/testsuite.in
index d2a508bf39e4c88ff59010056f6aaeba69d38dbe..103b890743b5401726dcada4c75f8d767d5d281f 100644
--- a/src/modules/Image/testsuite.in
+++ b/src/modules/Image/testsuite.in
@@ -1,54 +1,216 @@
-// $Id: testsuite.in,v 1.7 1998/04/16 01:57:04 mirar Exp $
-
-cond([[ master()->resolv("Image")->image ]],
-[[
-  test_true(programp(Image.image))
-  test_true(objectp(clone(Image.image)))
-  test_true(objectp(clone(Image.image,10,10)))
-  test_true(objectp(clone(Image.image,10,10,1,1,1)))
-  test_eq(clone(Image.image,10,12)->xsize(),10))
-  test_eq(clone(Image.image,10,12)->ysize(),12))
-  test_true(objectp(clone(Image.image,10,10,1,1,1)->copy()))
-  test_eq(clone(Image.image,10,12)->copy()->xsize(),10))
-  test_eq(clone(Image.image,10,12)->copy()->ysize(),12))
-dnl  test_true(objectp(clone(Image.image,10,10)->crop(2,2,3,3)))
-  test_true(objectp(clone(Image.image,10,10)->autocrop()))
-  test_true(objectp(clone(Image.image,10,10)->gray()))
-  test_true(objectp(clone(Image.image,10,10)->color(2,2,4)))
-  test_true(objectp(clone(Image.image,10,10)->invert()))
-  test_true(objectp(clone(Image.image,10,10)->threshold(10,20,30)))
-dnl matrix
-  test_true(objectp(clone(Image.image,10,10)->scale(2.1)))
-  test_eq(clone(Image.image,10,12)->scale(2.0)->xsize(),20)
-  test_eq(clone(Image.image,10,12)->scale(2.0)->ysize(),24)
-  test_true(objectp(clone(Image.image,10,10)->scale(0.2)))
-  test_true(objectp(clone(Image.image,10,10)->scale(2.0,0.2)))
-  test_true(objectp(clone(Image.image,10,10)->scale(0.2,2.2)))
-  test_true(objectp(clone(Image.image,10,10)->scale(0.2,2.2)))
-  test_true(objectp(clone(Image.image,10,10)->scale(0.2,2.2)))
-  test_eq(clone(Image.image,10,10)->scale(33,57)->xsize(),33)
-  test_eq(clone(Image.image,10,10)->scale(33,57)->ysize(),57)
-  test_true(stringp(clone(Image.image,10,10)->toppm()))
-dnl fromppm
-  test_true(stringp(clone(Image.image,10,10)->toppm()))
-  test_true(stringp(clone(Image.image,10,10)->togif()))
-  test_true(objectp(clone(Image.image,10,10)->paste(clone(Image.image,3,3),2,3)))
-dnl past_alpha
-dnl past_mask
-  test_do(clone(Image.image,10,10)->setcolor(2,2,2))
-  test_do(clone(Image.image,10,10)->setpixel(2,2,2,2,2))
-  test_do(clone(Image.image,10,10)->line(2,2,4,4,2,2,2))
-  test_do(clone(Image.image,10,10)->box(2,2,4,4,2,2,2))
-  test_do(clone(Image.image,10,10)->circle(2,2,4,4,2,2,2))
-dnl tuned_box
-  test_eq(clone(Image.image,10,10)->xsize(),10)
-  test_eq(clone(Image.image,10,10)->ysize(),10)
-  test_do(clone(Image.font))
-  test_do(clone(Image.font)->load("SRCDIR/testfont"))
-  test_any(object o=clone(Image.font); o->load("SRCDIR/testfont"); return o->height(),19)
-  test_any(object o=clone(Image.font); o->load("SRCDIR/testfont"); return o->write("foo")->xsize(),23)
-  test_any(object o=clone(Image.font); o->load("SRCDIR/testfont"); return
-o->write("foo")->ysize(),19)
-dnl  test_any(object o=clone(Image.font); o->load("SRCDIR/testfont"); o->write("foo"); clone(Image.image,100,100)->paste_alpha(o); return 1,1)
-]])
+test_any([[# 1 "-"
 
+
+#7 "testsuite.in.in"
+object img1=Image.PNM.decode("P1\n5 5\n0 1 1 1 1\n1 0 1 1 1\n1 1 0 1 1\n1 1 1 0 1\n1 1 1 1 0");
+object img2=Image.PNM.decode("P4\n5 5\nxИиш№");
+if (img1!=img2) return ( "differ\n" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#13 "testsuite.in.in"
+if ("hejsan, hoppsan" != MIME.decode_base64("aGVqc2FuLCBob3Bwc2Fu\n"))
+return ( "differ" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#18 "testsuite.in.in"
+object img1=Image.GIF.decode(MIME.decode_base64("R0lGODlhBQAFAIAAAAAAAP///ywAAAAABQAFAAACCAxwEWrY8BwoADs="));
+object img2=Image.PNM.decode("P4\n5 5\nx\00шиш№");
+if (img1!=img2) return ( "differ\n" );
+return "ok";
+
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#27 "testsuite.in.in"
+object img=Image.image();
+if (!img ||
+img->xsize() ||
+img->ysize()) return ( "have size" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#34 "testsuite.in.in"
+object img=Image.image(100,100);
+if (!img ||
+img->xsize()!=100 ||
+img->ysize()!=100) return ( "wrong size" );
+if (img!=0) return ( "wrong color" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#42 "testsuite.in.in"
+int x=1; while ((x<<1)>0) x=(x<<1)+1;
+if (!catch { Image.image(x,2); } ||
+!catch { Image.image(x/32768,32769); }) return ( "permitted" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#48 "testsuite.in.in"
+object img=Image.image(1000,1000,17,42,96);
+if (!img ||
+img->xsize()!=1000 ||
+img->ysize()!=1000) return ( "wrong size" );
+if (img!=({17,42,96})) return ( "wrong color" );
+return "ok";
+
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#59 "testsuite.in.in"
+object img=Image.image(10,10);
+img=img->test();
+if (equal(img->max(),({0,0,0}))) return ( "failed" );
+img->setpixel(2,2,0,255,0);
+if (img==img->invert()) return ( "failed" );
+return "ok";
+
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#70 "testsuite.in.in"
+object img=Image.image(100,100)->test();
+if (img!=img->copy()) return ( "differ" );
+if (img->copy(25,25,75,75)!=img->copy(25,25,75,75)) return ( "subregion differ" );
+if (img->copy(25,25,75,75)==img) return ( "subregion doesn't differ" );
+img->setpixel(2,2,0,255,0);
+if (img->copy()==img->invert()->copy()) return ( "copy of other doesn't differ" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#79 "testsuite.in.in"
+object img=Image.image(100,100)->test();
+if (img->clear()==img) return ( "doesn't differ" );
+if (img->clear(0,0,0)!=0) return ( "wrong color (black)" );
+if (img->clear(1,255,0)!=({1,255,0})) return ( "wrong color (color)" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#86 "testsuite.in.in"
+object img=Image.image(100,100)->test();
+if (img!=img->clone()) return ( "differ" );
+img->setpixel(2,2,0,255,0);
+if (img->clone()==img->invert()->clone()) return ( "clone of other doesn't differ" );
+return "ok";
+
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#96 "testsuite.in.in"
+array a=({0,0,0});
+array b=copy_value(a); b[0]=17; b[1]=42; b[2]=128;
+if (!equal( ({0,0,0}), a)) return ( "differ (1)" );
+if (!equal( ({17,42,128}), b)) return ( "differ (2)" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#103 "testsuite.in.in"
+if (!equal( ({0,0,0}), 
+Image.image(10,10,0,0,0)->max() ))
+return ( "erranous (1)" );
+if (!equal( ({17,42,36}), 
+Image.image(10,10,17,42,36)->max() ))
+return ( "erranous (2)" );
+if (!equal( ({17,42,36}), 
+Image.image(10,10,0,0,0)
+->setpixel(5,5,17,42,36)->max() ))
+return ( "erranous (3)" );
+if (!equal( ({17,42,36}), 
+Image.image(10,10,0,0,0)
+->setpixel(2,2,1,2,3)
+->setpixel(3,3,17,42,36)
+->setpixel(4,4,3,2,1)
+->max()))
+return ( "erranous (4)" );
+return "ok";
+
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#126 "testsuite.in.in"
+object img=Image.image(10,10,255,0,0);
+if (!equal(img->getpixel(5,5),({255,0,0}))) return ( "getpixel erranous" );
+img->setpixel(5,5,1,2,3);
+if (!equal(img->getpixel(5,5),({1,2,3}))) return ( "failed" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#133 "testsuite.in.in"
+object img=Image.image(10,10,255,0,0);
+img->setpixel(5,5,0,255,0,127);
+if (!equal(img->getpixel(5,5),({127,128,0}))) return ( "failed" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#139 "testsuite.in.in"
+object img=Image.image(100,100,0,0,0);
+foreach (({40,50,60}),int z)
+{ 
+img->line(50-z,0,50,50,255,255,255);
+img->line(50-z,100,50,50,255,255,255);
+img->line(0,50-z,50,50,255,255,255);
+img->line(100,50-z,50,50,255,255,255);
+}
+object img1=Image.GIF.decode(MIME.decode_base64(
+"R0lGODlhZABkAIAAAAAAAP///ywAAAAAZABkAAAC/wxwCGaq/l6UktZ6Mdat9sdsmziOpWl6WPMp\r\nYZrCcTxLLfLdi07Tve9brFQeXjB4RIKGQ5tQqYRGccTN7TWdZlPXWNeo1Wq7zqoLLBYjyWZXUa1W\r\ns526Kzoeby5H2L37npfn5kcUEGDY1icoqEe10qL4dMbIaFXW9pcIWBkFacknOTjJWenZaHWoSSpo\r\narO50yr0uvrpeBmkmDNLe1s3FhqayquUc0osLLozjEuIs4va+8xZfJt3SO28bIKdzNjXgaxdNTcd\r\nDi4dB+6qbT4qbhu73J79rt7Mjnwubt9dn99Pip+yd48GhVvF4h5BEPYOlrIFbOEbRw6tQUTH6xpF\r\njP9N9En0ISyhN3gfj1FkRbKkSVkcqQhUiSthRWYsWpZMxQDdC5swcUaksROmtxC7ggodKovmwKMP\r\nNQKNxJTVtTs+o9KaygWq1aEzYfHcuq2iU7D4IHUlG9DcV7RP3bElqPUtO7k36X5ca9fL2byl9vKV\r\nivfvo8CCXREu7CwuYjFEFwdM6rjpz8i/FFOO+eTwX5Ga+XK+nO4kaMaiR3cSOdn0NlGd6fJrLfe1\r\namKsZ2O+aBsoIdhoufEm6zu3l93Cwzb7bTUe8qjKi9eCmFp4c+fr7i0XSi767OzXe2LqrpI7dbfQ\r\noUs3pn20L0y511c7zx488+fjFaaHz74+D/lH99cJR2+efqD890ABADs="));
+if (img!=img1) return ( "differ" );
+return "ok";
+
+]], "ok")
+test_any([[# 1 "-"
+
+
+#153 "testsuite.in.in"
+object img=Image.image(100,100,0,0,0);
+img->line(40,0,0,40);
+if (!equal( ({0,0,0}), img->max() )) return ( "differ (reset)" );
+img->line(10,10,20,20,128,13,42);
+if (!equal( ({128,13,42}), img->max() )) return ( "differ (direct)" );
+img->setcolor(200,19,99);
+img->line(30,20,20,30);
+if (!equal( ({200,19,99}), img->max() )) return ( "differ (setcolor)" );
+return "ok";
+
+
+]], "ok")