]> git.imager.perl.org - imager.git/commitdiff
WIP, more coverage and fixes
authorTony Cook <tony@develop-help.com>
Thu, 22 Sep 2011 12:36:01 +0000 (22:36 +1000)
committerTony Cook <tony@develop-help.com>
Sat, 8 Oct 2011 03:39:46 +0000 (14:39 +1100)
iolayer.c
t/t07iolayer.t

index e451395422cb98abc54ed4f00c40638fa5d812ca..9318778b6e89cf683764be16da8a9867fec0702e 100644 (file)
--- a/iolayer.c
+++ b/iolayer.c
@@ -1198,7 +1198,9 @@ i_io_read_fill(io_glue *ig, ssize_t needed) {
   ssize_t rc;
   int good = 0;
 
-  /* this condition may be unused, callers should also be checking it */
+  IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%p, %d)\n", ig, (int)needed));
+
+  /* these conditions may be unused, callers should also be checking them */
   if (ig->error || ig->buf_eof)
     return 0;
 
@@ -1233,16 +1235,23 @@ i_io_read_fill(io_glue *ig, ssize_t needed) {
     needed -= rc;
   }
 
-  if (rc < 0)
+  if (rc < 0) {
     ig->error = 1;
-  else if (rc == 0)
+    IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc %d, setting error\n",
+                   (int)rc));
+  }
+  else if (rc == 0) {
     ig->buf_eof = 1;
+    IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc 0, setting eof\n"));
+  }
 
   if (good) {
     ig->read_ptr = buf_start;
     ig->read_end = work;
   }
   
+  IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill => %d, %u buffered\n", good,
+                 (unsigned)(ig->read_end - ig->read_ptr)));
   return good;
 }
 
@@ -1353,6 +1362,12 @@ ssize_t
 i_io_peekn(io_glue *ig, void *buf, size_t size) {
   IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn(%p, %p, %d)\n", ig, buf, (int)size));
 
+  if (size == 0) {
+    i_push_error(0, "peekn size must be positive");
+    IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (zero size)\n"));
+    return -1;
+  }
+
   if (ig->write_ptr) {
     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (write_ptr set)\n"));
     return -1;
@@ -1361,28 +1376,28 @@ i_io_peekn(io_glue *ig, void *buf, size_t size) {
   if (!ig->buffer)
     i_io_setup_buffer(ig);
 
-  if (!ig->read_ptr || size > ig->read_end - ig->read_ptr) {
-    if (ig->error) {
-      IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (error set)\n"));
-      return -1;
-    }
-    if (ig->buf_eof) {
-      IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => 0 (eof set)\n"));
-      return 0;
-    }
-
-    if (!i_io_read_fill(ig, size)) {
-      ssize_t result = ig->error ? -1 : 0;
-      IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => %d (read fill failed)\n",
-                     (int)result));
-      return result;
-    }
+  if ((!ig->read_ptr || size > ig->read_end - ig->read_ptr)
+      && !(ig->buf_eof || ig->error)) {
+    i_io_read_fill(ig, size);
   }
   
   if (size > ig->read_end - ig->read_ptr)
     size = ig->read_end - ig->read_ptr;
 
-  memcpy(buf, ig->read_ptr, size);
+  if (size)
+    memcpy(buf, ig->read_ptr, size);
+  else if (ig->buf_eof) {
+    IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => 0 (eof)\n"));
+    return 0;
+  }
+  else if (ig->error) {
+    IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (error)\n"));
+    return -1;
+  }
+  else {
+    IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() - size 0 but not eof or error!\n"));
+    return -1;
+  }
 
   IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => %d\n", (int)size));
 
@@ -1395,8 +1410,18 @@ i_io_putc_imp(io_glue *ig, int c) {
 
   if (!ig->buffered) {
     char buf = c;
-    ssize_t write_result = i_io_raw_write(ig, &buf, 1);
-    int result = write_result == 1 ? c : EOF;
+    ssize_t write_result;
+
+    if (ig->error)
+      return EOF;
+
+    write_result = i_io_raw_write(ig, &buf, 1);
+    int result = c;
+    if (write_result != 1) {
+      ig->error = 1;
+      result = EOF;
+      IOL_DEB(fprintf(IOL_DEBs, "  unbuffered putc() failed, setting error mode\n"));
+    }
     IOL_DEB(fprintf(IOL_DEBs, "  unbuffered: result %d\n", result));
 
     return result;
index 2d93f14b91cd159860cc09e8aec6a36bd8d25adb..75719108ae60a2039cdff3d929e8a96dd32c5d94 100644 (file)
@@ -1,6 +1,6 @@
 #!perl -w
 use strict;
-use Test::More tests => 159;
+use Test::More tests => 198;
 # for SEEK_SET etc, Fcntl doesn't provide these in 5.005_03
 use IO::Seekable;
 
@@ -504,7 +504,8 @@ SKIP:
     is($ops, "R8192>10;R8182>10;R8172>10;R8162>10;R8152>10;R8142>10;R8132>10;",
        "check we got the raw calls expected");
   }
-  { # peekn followed by errors
+  for my $buffered (1, 0) { # peekn followed by errors
+    my $buffered_desc = $buffered ? "buffered" : "unbuffered";
     my $read = 0;
     my $base = "abcdef";
     my $pos = 0;
@@ -527,18 +528,48 @@ SKIP:
       return $result;
     };
     my $io = Imager::io_new_cb(undef, $reader, undef, undef);
-    is($io->peekn(5), "abcde", "peekn until just before error");
-    is($io->peekn(6), "abcdef", "peekn until error");
-    is($io->peekn(7), "abcdef", "peekn past error");
-    ok(!$io->error, "should be no error indicator, since data buffered");
-    ok(!$io->eof, "should be no eof indicator, since data buffered");
+    ok($io, "make $buffered_desc cb with error after 6 bytes");
+    is($io->peekn(5), "abcde",
+       "peekn until just before error ($buffered_desc)");
+    is($io->peekn(6), "abcdef", "peekn until error ($buffered_desc)");
+    is($io->peekn(7), "abcdef", "peekn past error ($buffered_desc)");
+    ok(!$io->error,
+       "should be no error indicator, since data buffered ($buffered_desc)");
+    ok(!$io->eof,
+       "should be no eof indicator, since data buffered ($buffered_desc)");
 
     # consume it
-    is($io->read2(6), "abcdef", "consume the buffer");
-    is($io->peekn(10), undef, "should get an error indicator");
-    ok($io->error, "should be an error state");
+    is($io->read2(6), "abcdef", "consume the buffer ($buffered_desc)");
+    is($io->peekn(10), undef,
+       "peekn should get an error indicator ($buffered_desc)");
+    ok($io->error, "should be an error state ($buffered_desc)");
+    ok(!$io->eof, "but not eof ($buffered_desc)");
+  }
+  { # peekn on an empty file
+    my $io = Imager::io_new_buffer("");
+    is($io->peekn(10), "", "peekn on empty source");
+    ok($io->eof, "should be in eof state");
+    ok(!$io->error, "but not error");
+  }
+  { # peekn on error source
+    my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef);
+    is($io->peekn(10), undef, "peekn on empty source");
+    ok($io->error, "should be in error state");
     ok(!$io->eof, "but not eof");
   }
+  { # peekn on short source
+    my $io = Imager::io_new_buffer("abcdef");
+    is($io->peekn(4), "abcd", "peekn 4 on 6 byte source");
+    is($io->peekn(10), "abcdef", "followed by peekn 10 on 6 byte source");
+    is($io->peekn(10), "abcdef", "and again, now eof is set");
+  }
+  { # peekn(0)
+    Imager::i_clear_error();
+    my $io = Imager::io_new_buffer("abcdef");
+    is($io->peekn(0), undef, "peekn 0 on 6 byte source");
+    my $msg = Imager->_error_as_msg;
+    is($msg, "peekn size must be positive");
+  }
   { # getc through a whole file (buffered)
     my $io = Imager::io_new_buffer($base);
     my $out = '';
@@ -622,6 +653,51 @@ SKIP:
     ok($io->error, "io marked error");
     ok(!$io->eof, "but not eof");
   }
+  { # initial putc
+    my $io = Imager::io_new_bufchain();
+    is($io->putc(ord "A"), ord "A", "initial putc buffered");
+    is($io->close, 0, "close it");
+    is(Imager::io_slurp($io), "A", "check it was written");
+  }
+  { # initial putc - unbuffered
+    my $io = Imager::io_new_bufchain();
+    $io->set_buffered(0);
+    is($io->putc(ord "A"), ord "A", "initial putc unbuffered");
+    is($io->close, 0, "close it");
+    is(Imager::io_slurp($io), "A", "check it was written");
+  }
+  { # putc unbuffered with error
+    my $io = Imager::io_new_cb(undef, undef, undef, undef);
+    $io->set_buffered(0);
+    is($io->putc(ord "A"), -1, "initial putc unbuffered error");
+    ok($io->error, "io in error");
+    is($io->putc(ord "B"), -1, "still in error");
+  }
+  { # putc while in read state
+    my $io = Imager::io_new_cb(sub { 1 }, sub { return "AA" }, undef, undef);
+    is($io->getc, ord "A", "read to setup read buffer");
+    is($io->putc(ord "B"), -1, "putc should fail");
+  }
+  { # buffered putc error handling
+    # tests the check for error state in the buffered putc code
+    my $io = Imager::io_new_cb(undef, undef, undef, undef);
+    $io->putc(ord "A");
+    ok(!$io->flush, "flush should fail");
+    ok($io->error, "should be in error state");
+    is($io->putc(ord "B"), -1, "check for error");
+  }
+  { # buffered putc flush error handling
+    # test handling of flush failure and of the error state resulting
+    # from that
+    my $io = Imager::io_new_cb(undef, undef, undef, undef);
+    my $i = 0;
+    while (++$i < 100_000 && $io->putc(ord "A") == ord "A") {
+      # until we have to flush and fail doing do
+    }
+    is($i, 8193, "should have failed on 8193rd byte");
+    ok($io->error, "should be in error state");
+    is($io->putc(ord "B"), -1, "next putc should fail");
+  }
 }
 
 Imager->close_log;