int
PipeControlChannel::createNamedPipe(const bsl::string& pipeName)
{
    BALL_LOG_SET_CATEGORY(LOG_CATEGORY);

    BALL_LOG_TRACE << "Creating named pipe '" << pipeName << "'"
                   << BALL_LOG_END;

    if (bdls::PipeUtil::isOpenForReading(pipeName)) {
        BALL_LOG_ERROR << "Named pipe '" << pipeName << "' already exists"
                       << BALL_LOG_END;
        return -2;
    }

    d_impl.d_windows.d_handle =
        CreateNamedPipe(pipeName.c_str(),
                        PIPE_ACCESS_INBOUND,
                        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                        PIPE_UNLIMITED_INSTANCES,
                        MAX_PIPE_BUFFER_LEN,
                        MAX_PIPE_BUFFER_LEN,
                        2000, // default timeout in ms for pipe operations
                        NULL);

    if (INVALID_HANDLE_VALUE == d_impl.d_windows.d_handle) {
        BALL_LOG_TRACE << "Failed to create named pipe '" << pipeName
                       << "': "
                       << describeWin32Error(GetLastError())
                       << BALL_LOG_END;
        return -1;
    }

    return 0;
}
// ACCESSORS
const char *TestReader::documentEncoding() const {
    return d_encoding.c_str();
}
int
PipeControlChannel::createNamedPipe(const bsl::string& pipeName)
{
    BALL_LOG_SET_CATEGORY(LOG_CATEGORY);
//  BSLS_ASSERT(0 == d_impl.d_unix.d_readFd);

    if (0 != d_impl.d_unix.d_readFd) {
        return -7;                                                    // RETURN
    }

    if (bdls::FilesystemUtil::exists(pipeName)) {
       // The pipe already exists, but it may have been left over from a
       // previous crash.  Check whether there is a reader on the pipe, in
       // which case fail; otherwise unlink the pipe and continue.
       if (bdls::PipeUtil::isOpenForReading(pipeName)) {
           BALL_LOG_ERROR << "Named pipe "
                             "'" << pipeName << "' "
                             "is already in use by another process"
                          << BALL_LOG_END;
           return -2;                                                 // RETURN
       }
       bdls::FilesystemUtil::remove(pipeName.c_str());
    }

    // TBD: USE BDEU_PATHUTIL
    bsl::string dirname;
    if (0 == bdls::PathUtil::getDirname(&dirname, pipeName)) {
        if (!bdls::FilesystemUtil::exists(dirname)) {
            BALL_LOG_ERROR << "Named pipe directory "
                              "'" << dirname << "' "
                              "does not exist"
                           << BALL_LOG_END;
            return -3;                                                // RETURN
        }
    }

    const char *rawPipeName = pipeName.c_str();

    int rc         = mkfifo(rawPipeName, 0666);

    if (0 != rc) {
        int savedErrno = errno;

        BALL_LOG_ERROR << "Unable to create pipe "
                          "'"          << rawPipeName               << "'"
                          ": errno = " << savedErrno                << " "
                          "("          << bsl::strerror(savedErrno) << ")"
                       << BALL_LOG_END;
        return -4;                                                    // RETURN
    }

    d_impl.d_unix.d_readFd = open(rawPipeName, O_RDONLY | O_NONBLOCK);

    if (-1 == d_impl.d_unix.d_readFd) {
        int savedErrno = errno;

        BALL_LOG_ERROR << "Cannot open pipe "
                          "'"           << rawPipeName               << "' "
                          "for reading"
                          ": errno = "  << savedErrno                << " "
                          "("           << bsl::strerror(savedErrno) << ")"
                       << BALL_LOG_END;
        return -5;                                                    // RETURN
    }

    d_impl.d_unix.d_writeFd = open(rawPipeName, O_WRONLY);
    if (-1 == d_impl.d_unix.d_writeFd) {
        int savedErrno = errno;

        BALL_LOG_ERROR << "Failed to open named pipe "
                          "'"           << rawPipeName               << "' "
                          "for writing"
                          ": errno = "  << savedErrno                << " "
                          "("           << bsl::strerror(savedErrno) << ")"
                       << BALL_LOG_END;
        return -6;                                                    // RETURN
    }

    BALL_LOG_TRACE << "Created named pipe '" << rawPipeName << "'"
                   << BALL_LOG_END;

    return 0;
}
Exemple #4
0
int main(int argc, char *argv[])
{
    int test = argc > 1 ? bsl::atoi(argv[1]) : 0;
    int verbose = argc > 2;
    int veryVerbose = argc > 3;
    int veryVeryVerbose = argc > 4;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;;

    switch (test) { case 0:  // Zero is always the leading case.
      case 8: {
        // --------------------------------------------------------------------
        // TESTING CONCERN: EOF IS STREAMED CORRECTLY
        //
        // Concerns:
        //   * That 'xsputn' copies EOF when it appears within a buffer
        //     boundary.
        //
        //   * That 'xsputn' copies EOF when it appears as the first character
        //     in a buffer (i.e., when it crosses a buffer boundary).
        //
        // Plan:
        //  Iterate over a set of test vectors varying in buffer size and
        //  length of data to write.  For each test vector, instantiate a
        //  'btlb::PooledBlobBufferFactory', 'mF', allocate a 'btlb::Blob',
        //  'mC', and use 'mC' to instantiate a 'btlb::BlobStreamBuf', 'mX'.
        //  Write the specified number of bytes to 'mX' using 'sputn', and
        //  verify the length of 'mC'.  Read the specified number of buffers
        //  from 'mX', and verify the result, and the get area offset of 'mX'.
        //
        //  Instantiate a 'btlb::PooledBlobBufferFactory', 'mF', allocate a
        //  'btlb::Blob', 'mC', and use 'mC' to instantiate a
        //  'btlb::BlobStreamBuf, 'mX'.  Iterate over an input  buffer whose
        //  length is more than the size of 'mC', but less than twice the size
        //  of 'mC'.  On each iteration, write the input buffer into 'mX',
        //  substituting the i'th character for EOF.  Read back the data form
        //  'mX', and verify the result.
        //
        // Testing:
        //   Concern: EOF is streamed correctly
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Concern: EOF Is Streamed Correctly" << endl
                 << "==================================" << endl;
        }

        bslma::TestAllocator ta(veryVeryVerbose);
        {
            const struct {
                int d_line;          // source line number
                int d_bufferSize;    // factory buffer size
                int d_dataLength;    // length of data to read and write
            } DATA[] = {
                //Line  Buffer Size  Data Length
                //----  -----------  -----------
                { L_,   1,           1,         },
                { L_,   1,           5,         },
                { L_,   2,           1,         },
                { L_,   2,           2,         },
                { L_,   2,           5,         },
                { L_,   3,           9,         },
                { L_,   37,          101,       },
            };
            enum { k_DATA_SIZE = sizeof DATA / sizeof *DATA };

            const bsl::ios_base::seekdir  CUR     = bsl::ios_base::cur;
            const bsl::ios_base::openmode OUT1    = bsl::ios_base::out;
            const bsl::ios_base::openmode IN1     = bsl::ios_base::in;
            const int EOF_VAL = btlb::InBlobStreamBuf::traits_type::eof();

            for (int i = 0; i < k_DATA_SIZE; ++i) {
                const int LINE        = DATA[i].d_line;
                const int BUFFER_SIZE = DATA[i].d_bufferSize;
                const int DATA_LENGTH = DATA[i].d_dataLength;

                if (verbose) {
                    P_(i); P_(LINE);
                    P_(BUFFER_SIZE); P(DATA_LENGTH);
                }

                testBlobBufferFactory fa(&ta, BUFFER_SIZE);
                fa.setGrowFlag(false);

                btlb::Blob blob(&fa, &ta);
                {
                    btlb::InBlobStreamBuf  in(&blob);
                    btlb::OutBlobStreamBuf out(&blob);
                    char *EOFS = (char *)ta.allocate(DATA_LENGTH);
                    bsl::memset(EOFS, EOF_VAL, DATA_LENGTH);

                    // Write out data.
                    LOOP2_ASSERT(i, LINE, DATA_LENGTH ==
                                            out.sputn(EOFS, DATA_LENGTH));
                    LOOP2_ASSERT(i, LINE, DATA_LENGTH ==
                                                 out.pubseekoff(0, CUR, OUT1));
                    LOOP2_ASSERT(i, LINE, DATA_LENGTH == blob.length());

                    // Read in data.
                    char *result = (char *)ta.allocate(DATA_LENGTH);
                    LOOP2_ASSERT(i, LINE, DATA_LENGTH ==
                                                in.sgetn(result, DATA_LENGTH));
                    LOOP2_ASSERT(i, LINE, DATA_LENGTH ==
                                                   in.pubseekoff(0, CUR, IN1));
                    LOOP2_ASSERT(i, LINE, 0 == bsl::memcmp(EOFS,
                                                           result,
                                                           DATA_LENGTH));
                    ta.deallocate(EOFS);
                    ta.deallocate(result);
                }
            }

            //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            enum {
                k_BUFFER_SIZE = 8,
                k_DATA_LENGTH = 12
            };
            ASSERT(k_DATA_LENGTH > k_BUFFER_SIZE);
            ASSERT(k_DATA_LENGTH < k_BUFFER_SIZE * 2);

            testBlobBufferFactory fa(&ta, k_BUFFER_SIZE);
            fa.setGrowFlag(false);

            char data[k_DATA_LENGTH];
            char result[k_DATA_LENGTH];
            bsl::memset(data, '*', k_DATA_LENGTH);

            for (int i = 0; i < k_DATA_LENGTH; ++i) {
                btlb::Blob blob(&fa, &ta);
                {
                    btlb::InBlobStreamBuf  in(&blob);
                    btlb::OutBlobStreamBuf out(&blob);
                    data[i] = EOF_VAL;
                    LOOP_ASSERT(i, k_DATA_LENGTH ==
                                               out.sputn(data, k_DATA_LENGTH));
                    LOOP_ASSERT(i, k_DATA_LENGTH ==
                                                 out.pubseekoff(0, CUR, OUT1));
                    LOOP_ASSERT(i, k_DATA_LENGTH == blob.length());
                    LOOP_ASSERT(i, k_DATA_LENGTH == in.sgetn(result,
                                                           k_DATA_LENGTH));
                    LOOP_ASSERT(i, 0 == bsl::memcmp(data,
                                                    result,
                                                    k_DATA_LENGTH));
                    data[i] = '*';
                }
            }
        }
        ASSERT(0 <  ta.numAllocations());
        ASSERT(0 == ta.numBytesInUse());
      }  break;
      case 7: {
        // --------------------------------------------------------------------
        // TESTING 'xsgetn' AND 'xsputn' FUNCTIONS
        //
        // Concerns:
        //   * That 'xsputn' returns the requested number of bytes when that
        //     number is less than the current buffer capacity.
        //
        //   * That 'xsputn' returns the requested number of bytes when that
        //     number is greater than the current buffer capacity.
        //
        //   * That 'xsgetn' returns the requested number of bytes when that
        //     number is less than the current buffer capacity.
        //
        //   * That 'xsgetn' returns the requested number of bytes when that
        //     number is greater than the current buffer capacity.
        //
        // Plan:
        //   Iterate over a set of test vectors varying in buffer size and
        //   length of data to write.  For each test vector, instantiate a
        //   'btlb::PooledBlobBufferFactory', 'mF', allocate a
        //   'btlb::Blob', 'mC', and use 'mC' to instantiate a
        //   'btlb::BlobStreamBuf', 'mX'.  Write the specified
        //   number of bytes to 'mX' using 'sputn', and verify the length of
        //   'mC'.  Read the specified number of buffers from 'mX', and verify
        //   the result, and the get area offset of 'mX'.
        //
        // Testing:
        //   bsl::streamsize xsgetn(char_type       *destination,
        //                          bsl::streamsize  numChars);
        //   bsl::streamsize xsputn(const char_type *source,
        //                          bsl::streamsize  numChars);
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Testing 'xsgetn' and 'xsputn' Functions" << endl
                 << "=======================================" << endl;
        }

        bslma::TestAllocator ta(veryVeryVerbose);
        {
            const struct {
                int d_line;          // source line number
                int d_bufferSize;    // factory buffer size
                int d_dataLength;    // length of data to read and write
            } DATA[] = {
                //Line  Buffer Size  Data Length
                //----  -----------  -----------
                { L_,   1,           1,         },
                { L_,   1,           5,         },
                { L_,   2,           1,         },
                { L_,   2,           2,         },
                { L_,   2,           5,         },
                { L_,   3,           9,         },
                { L_,   37,          101,       },
            };
            enum { k_DATA_SIZE = sizeof DATA / sizeof *DATA };

            const bsl::ios_base::seekdir  CUR  = bsl::ios_base::cur;
            const bsl::ios_base::openmode OUT1 = bsl::ios_base::out;
            const bsl::ios_base::openmode IN1  = bsl::ios_base::in;

            for (int i = 0; i < k_DATA_SIZE; ++i) {
                const int LINE        = DATA[i].d_line;
                const int k_BUFFER_SIZE = DATA[i].d_bufferSize;
                const int k_DATA_LENGTH = DATA[i].d_dataLength;

                if (verbose) {
                    P_(i); P_(LINE);
                    P_(k_BUFFER_SIZE); P(k_DATA_LENGTH);
                }

                testBlobBufferFactory fa(&ta, k_BUFFER_SIZE);
                fa.setGrowFlag(false);

                btlb::Blob blob(&fa, &ta);
                {
                    btlb::InBlobStreamBuf  in(&blob);
                    btlb::OutBlobStreamBuf out(&blob);
                    char *HASHMARKS = (char *)ta.allocate(k_DATA_LENGTH);
                    bsl::memset(HASHMARKS, '#', k_DATA_LENGTH);

                    // Write out data.
                    LOOP2_ASSERT(i, LINE, k_DATA_LENGTH ==
                                          out.sputn(HASHMARKS, k_DATA_LENGTH));
                    LOOP2_ASSERT(i, LINE, k_DATA_LENGTH ==
                                                 out.pubseekoff(0, CUR, OUT1));
                    LOOP2_ASSERT(i, LINE, k_DATA_LENGTH == blob.length());

                    // Read in data.
                    char *result = (char *)ta.allocate(k_DATA_LENGTH);
                    LOOP2_ASSERT(i, LINE, k_DATA_LENGTH ==
                                              in.sgetn(result, k_DATA_LENGTH));
                    LOOP2_ASSERT(i, LINE, k_DATA_LENGTH ==
                                                   in.pubseekoff(0, CUR, IN1));
                    LOOP2_ASSERT(i, LINE, 0 == bsl::memcmp(HASHMARKS,
                                                           result,
                                                           k_DATA_LENGTH));
                    ta.deallocate(HASHMARKS);
                    ta.deallocate(result);
                }
            }
        }
        ASSERT(0 <  ta.numAllocations());
        ASSERT(0 == ta.numBytesInUse());
      }  break;
      case 6: {
        // --------------------------------------------------------------------
        // TESTING 'reset' FUNCTION
        //
        // Concerns:
        //   * That 'reset' called with the default argument resets the get
        //     and put areas, but does not affect the underlying buffer chain.
        //
        //   * That 'reset' called with a buffer chain argument both resets
        //     the underlying buffer chain to the specified buffer chain, and
        //     resets the get and put areas.
        //
        // Plan:
        //   Create two modifiable 'btlb::Blob' objects, 'mCa'
        //   and 'mCb'.  Create a modifiable 'btlb::BlobStreamBuf'
        //   'mX', instantiated with 'mCa', and a non-modifiable reference to
        //   'mX' named 'X'.  Using 'X', verify that 'mX' is supported by
        //   'mCa'.  Adjust the get and put areas by calling 'pubseekpos' on
        //   'mX'.  Call 'reset' with the default argument on 'mX', and verify
        //   using 'X', and by calling 'pubseekoff' on 'mX', that the get and
        //   put areas have been reset.  Call 'reset' with argument 'mCb' on
        //   'mX', and verify as before that the get and put areas have been
        //   reset.  Additionally verify that 'mX' is not supported by 'mCb'.
        //
        // Testing:
        //   void reset(btlb::Blob *blob);
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Testing 'reset' Function" << endl
                 << "========================" << endl;
        }

        bslma::TestAllocator ta(veryVeryVerbose);
        if (verbose) cout << "\nTesting bcesb_OutBlobStreamBuf." << endl;
        {
            enum {
                k_BUFFER_SIZE_A = 16,    // buffer size for factory "A"
                k_BUFFER_SIZE_B = 32,    // buffer size for factory "B"
                k_SEEK_OFFSET   = 37,    // arbitrary offset
                k_DATA_LENGTH   = 64     // amount of data to write to stream
            };

            testBlobBufferFactory factoryA(&ta, k_BUFFER_SIZE_A);
            factoryA.setGrowFlag(false);
            btlb::Blob mCaI(&factoryA, &ta); btlb::Blob* mCa = &mCaI;
            ASSERT(0 == mCa->length());
            ASSERT(0 == mCa->numBuffers());

            testBlobBufferFactory factoryB(&ta, k_BUFFER_SIZE_B);
            factoryB.setGrowFlag(false);
            btlb::Blob mCbI(&factoryB, &ta); btlb::Blob* mCb = &mCbI;
            ASSERT(0 == mCb->length());
            ASSERT(0 == mCb->numBuffers());

            const bsl::ios_base::seekdir  CUR  = bsl::ios_base::cur;
            const bsl::ios_base::openmode OUT1 = bsl::ios_base::out;

            {
                btlb::OutBlobStreamBuf mX(mCa);
                const btlb::OutBlobStreamBuf& X = mX;
                ASSERT(X.data() == mCa);
                ASSERT(X.data() != mCb);
                ASSERT(0 == mX.pubseekoff(0, CUR, OUT1));

                const bsl::string HASHMARKS(k_DATA_LENGTH, '#');
                bsl::ostream      out(&mX);

                out << HASHMARKS << flush;

                ASSERT(k_DATA_LENGTH == mX.pubseekoff(0, CUR, OUT1));
                ASSERT(k_DATA_LENGTH == mCa->length());
                ASSERT(4 == mCa->numBuffers());
                ASSERT(0 == mCb->length());
                ASSERT(0 == mCb->numBuffers());

                mX.reset();
                ASSERT(X.data() == mCa);
                ASSERT(X.data() != mCb);
                ASSERT(k_DATA_LENGTH == mX.pubseekoff(0, CUR, OUT1));
                ASSERT(k_DATA_LENGTH == mCa->length());
                ASSERT(4 == mCa->numBuffers());
                ASSERT(0 == mCb->length());
                ASSERT(0 == mCb->numBuffers());

                out << HASHMARKS << flush;

                ASSERT(2 * k_DATA_LENGTH == mX.pubseekoff(0, CUR, OUT1));
                ASSERT(8 == mCa->numBuffers());
                ASSERT(0 == mCb->length());
                ASSERT(0 == mCb->numBuffers());

                mX.reset(mCb);
                ASSERT(X.data() != mCa);
                ASSERT(X.data() == mCb);
                ASSERT(0 == mX.pubseekoff(0, CUR, OUT1));
                ASSERT(2 * k_DATA_LENGTH == mCa->length());
                ASSERT(8 == mCa->numBuffers());;
                ASSERT(0 == mCb->length());
                ASSERT(0 == mCb->numBuffers());

                out << HASHMARKS << flush;

                ASSERT(k_DATA_LENGTH == mX.pubseekoff(0, CUR, OUT1));
                ASSERT(2 * k_DATA_LENGTH == mCa->length());
                ASSERT(8 == mCa->numBuffers());;
                ASSERT(k_DATA_LENGTH == mCb->length());
                ASSERT(2 == mCb->numBuffers());

                mCbI.removeAll();

                ASSERT(0   == mCb->length());
                ASSERT(0   == mCb->numBuffers());
                ASSERT(mCb == X.data());

                mX.reset();

                ASSERT(mCa != X.data());
                ASSERT(mCb == X.data());
            }
        }

        if (verbose) cout << "\nTesting bcesb_InBlobStreamBuf." << endl;
        {
            enum {
                k_BUFFER_SIZE_A = 16,    // buffer size for factory "A"
                k_BUFFER_SIZE_B = 32,    // buffer size for factory "B"
                k_SEEK_OFFSET   = 5     // arbitrary offset
            };

            testBlobBufferFactory factoryA(&ta, k_BUFFER_SIZE_A);
            factoryA.setGrowFlag(false);
            btlb::Blob mCaI(&factoryA, &ta); btlb::Blob* mCa = &mCaI;
            ASSERT(0 == mCa->length());
            ASSERT(0 == mCa->numBuffers());

            testBlobBufferFactory factoryB(&ta, k_BUFFER_SIZE_B);
            factoryB.setGrowFlag(false);
            btlb::Blob mCbI(&factoryB, &ta); btlb::Blob* mCb = &mCbI;
            ASSERT(0 == mCb->length());
            ASSERT(0 == mCb->numBuffers());

            const bsl::ios_base::seekdir  CUR = bsl::ios_base::cur;
            const bsl::ios_base::openmode IN1 = bsl::ios_base::in;

            {
                mCa->setLength(10); bsl::memset(mCa->buffer(0).data(), 1, 10);
                mCb->setLength(10); bsl::memset(mCb->buffer(0).data(), 2, 10);

                btlb::InBlobStreamBuf mX(mCa);
                const btlb::InBlobStreamBuf& X = mX;
                ASSERT(X.data() == mCa);
                ASSERT(X.data() != mCb);
                ASSERT(0 == mX.pubseekoff(0, CUR, IN1));

                bsl::istream      in(&mX);

                ASSERT(k_SEEK_OFFSET == mX.pubseekpos(k_SEEK_OFFSET, IN1));
                char read;
                in >> read;
                ASSERT(1 == read);

                mX.reset();
                ASSERT(X.data() == mCa);
                ASSERT(X.data() != mCb);
                ASSERT(0 == mX.pubseekoff(0, CUR, IN1));

                in >> read;
                ASSERT(1 == read);

                mX.reset(mCb);
                ASSERT(X.data() != mCa);
                ASSERT(X.data() == mCb);
                ASSERT(0 == mX.pubseekoff(0, CUR, IN1));

                in >> read;
                ASSERT(2 == read);

                ASSERT(k_SEEK_OFFSET == mX.pubseekpos(k_SEEK_OFFSET, IN1));
                ASSERT(k_SEEK_OFFSET == mX.pubseekoff(0, CUR, IN1));
            }
        }
        ASSERT(0 <  ta.numAllocations());
        ASSERT(0 == ta.numBytesInUse());
      }  break;
      case 5: {
      } break;
      case 4: {
      } break;
      case 3: {
      } break;
      case 2: {
        // --------------------------------------------------------------------
        // TESTING PRIMARY MANIPULATORS (BOOTSTRAP)
        //
        // Concerns:
        //   * That it is possible to instantiate a
        //     'btlb::BlobStreamBuf' object with a variety of
        //     'btlb::Blob' parameters.
        //
        //   * That 'sync' and 'overflow' update the chain length.
        //
        // Plan:
        //   Iterate over a set of test vectors varying in buffer size.  For
        //   each test vector, instantiate a modifiable
        //   'btlb::BlobStreamBuf', 'mX', and a non-modifiable
        //   reference to 'mX' named 'X'.  Write data of length 3 times the
        //   specified buffer size to 'mX' in chunks of buffer size, 'sync'ing
        //   'mX' after each write, and verifying the chain length and number
        //   of buffers using 'X'.
        //
        // Testing:
        //   btlb::BlobStreamBuf(btlb::Blob *blob);
        //   ~btlb::BlobStreamBuf();
        //   int_type overflow(int_type c =
        //                                 bsl::streambuf::traits_type::eof());
        //   int sync();
        //   const btlb::Blob *data() const;
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "TESTING PRIMARY MANIPULATORS (BOOTSTRAP)" << endl
                 << "========================================" << endl;
        }

        bslma::TestAllocator ta(veryVeryVerbose);
        {
            const struct {
                int d_line;          // source line number
                int d_bufferSize;    // factory buffer size
            } DATA[] = {
                //Line  Buffer Size
                //----  -----------
                { L_,   1,         },
                { L_,   2,         },
                { L_,   4,         },
                { L_,   11,        },
                { L_,   101,       },
                { L_,   1024,      },
                { L_,   4096,      },
            };
            enum { k_DATA_SIZE = sizeof DATA / sizeof *DATA };

            for (int i = 0; i < k_DATA_SIZE; ++i) {
                const int LINE        = DATA[i].d_line;
                const int k_BUFFER_SIZE = DATA[i].d_bufferSize;

                testBlobBufferFactory fa(&ta, k_BUFFER_SIZE);
                fa.setGrowFlag(false);

                btlb::Blob blob(&fa, &ta);
                btlb::OutBlobStreamBuf mX(&blob);
                const btlb::OutBlobStreamBuf&         X = mX;
                const bsl::string  HASHMARKS(k_BUFFER_SIZE, '#');

                if (verbose) {
                    P_(i); P_(LINE); P(k_BUFFER_SIZE);
                }

                enum { k_NUM_ITERATIONS = 3 };
                for (int j = 0; j < k_NUM_ITERATIONS; ++j) {
                    const int PRE_PUT_LENGTH   = j * k_BUFFER_SIZE;
                    const int POST_PUT_LENGTH  = PRE_PUT_LENGTH + 1;
                    const int POST_SYNC_LENGTH = (j + 1) * k_BUFFER_SIZE;

                    LOOP3_ASSERT(i, LINE, j,
                                 PRE_PUT_LENGTH == X.data()->length());
                    LOOP3_ASSERT(i, LINE, j, j == X.data()->numBuffers());

                    mX.sputn(HASHMARKS.c_str(), HASHMARKS.length());
                    LOOP3_ASSERT(i, LINE, j,
                                 POST_PUT_LENGTH == X.data()->length());
                    LOOP3_ASSERT(i, LINE, j, j + 1 == X.data()->numBuffers());

                    mX.pubsync();
                    LOOP3_ASSERT(i, LINE, j,
                                 POST_SYNC_LENGTH == X.data()->length());
                    LOOP3_ASSERT(i, LINE, j, j + 1 == X.data()->numBuffers());
                }
            }
        }
        ASSERT(0 <  ta.numAllocations());
        ASSERT(0 == ta.numBytesInUse());
      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST:
        //   Developers' Sandbox.
        //
        // Concerns:
        //
        // Plan:
        //
        // Tactics:
        //   - Ad Hoc Test Data Selection Method
        //   - Brute Force Implementation Technique
        //
        // Testing:
        //   This "test" *exercises* basic functionality, but *tests* nothing.
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "BREATHING TEST" << endl
                          << "==============" << endl;

        bslma::TestAllocator ta(veryVeryVerbose);

        if (verbose) cout << "\nTesting bcesb_InBlobStreamBuf." << endl;
        {
            typedef btlb::InBlobStreamBuf Obj;

            enum { k_MAX_k_BUFFER_SIZE = 20 };
            for(int i = 0; i < k_MAX_k_BUFFER_SIZE; ++i) {
                const bsl::size_t  k_BUFFER_SIZE = i + 1;

                testBlobBufferFactory fa(&ta, k_BUFFER_SIZE);
                //fa.setGrowFlag(false);

                btlb::Blob blob(&fa, &ta);
                {
                    Obj mX(&blob); const Obj&    X = mX;
                    bsl::istream stream(&mX);
                    ASSERT(stream.rdbuf() == &mX);

                    if (verbose) {
                        P_(i); P(k_BUFFER_SIZE);
                    }

                    {
                        int j;
                        ASSERT(!(stream >> j));
                        ASSERT(!stream);
                        stream.clear();
                    }

                    {
                        int posInBuf = 0;
                        int currentBuf = 0;
                        blob.setLength(k_MAX_k_BUFFER_SIZE);
                        for (int j = 0; j < k_MAX_k_BUFFER_SIZE; ++j) {
                            if (posInBuf == blob.buffer(currentBuf).size()) {
                                ++currentBuf;
                                posInBuf = 0;
                            }
                            *(blob.buffer(currentBuf).data() + posInBuf) =
                                                                       'A' + j;
                            if (veryVerbose) {
                                bsl::cout << "Wrote " << j << " at offset "
                                          << posInBuf << " in buffer "
                                          << currentBuf << bsl::endl;
                            }
                            ++posInBuf;
                        }

                    }

                    {
                        int j = 0;
                        char c;
                        while (stream >> c) {
                            LOOP_ASSERT(j, c == 'A' + j);
                            if (verbose) {
                                T_; P_(c); P(j);
                            }
                            ASSERT(stream.rdbuf() == &mX);
                            ASSERT(stream.unget());
                            if (j) {
                                ASSERT(stream.unget());
                                ASSERT(stream >> c)
                                LOOP_ASSERT(j, c == 'A' + j - 1);
                            }
                            else {
                                ASSERT(!stream.unget());
                                stream.clear();
                            }
                            ASSERT(stream >> c)
                            LOOP_ASSERT(j, c == 'A' + j);
                            ++j;

                        }
                        ASSERT(k_MAX_k_BUFFER_SIZE == j);
                    }

                    ASSERT(!stream);
                    stream.clear();
                    stream.seekg(0);
                    for (int j = 0; j < k_MAX_k_BUFFER_SIZE; ++j) {
                        for (int k = 0; k < k_MAX_k_BUFFER_SIZE; ++k) {
                            char c;
                            stream.seekg(j);
                            ASSERT(stream >> c);
                            LOOP2_ASSERT(j, k, c == j + 'A');
                            stream.seekg(k);
                            ASSERT(stream >> c);
                            LOOP2_ASSERT(j, k, c == k + 'A');
                        }
                    }

                    bsl::string str;
                    ASSERT(!(stream >> str));
                    stream.clear();
                    stream.seekg(0);
                    ASSERT(stream >> str);
                    ASSERT(k_MAX_k_BUFFER_SIZE == str.length());
                    ASSERT('A' == str[0]);
                    ASSERT('A' + k_MAX_k_BUFFER_SIZE - 1 ==
                                                 str[k_MAX_k_BUFFER_SIZE - 1]);
                }
            }
        }
        if (verbose) cout << "\nTesting bcesb_OutBlobStreamBuf." << endl;
        {
            enum { k_MAX_k_BUFFER_SIZE = 20 };
            for(int i = 0; i < k_MAX_k_BUFFER_SIZE; ++i) {
                const bsl::size_t  k_BUFFER_SIZE = i + 1;

                testBlobBufferFactory fa(&ta, k_BUFFER_SIZE);
                //fa.setGrowFlag(false);

                btlb::Blob blob(&fa, &ta);
                {
                    btlb::OutBlobStreamBuf outbuf(&blob);
                    bsl::ostream ostream(&outbuf);
                    btlb::InBlobStreamBuf inbuf(&blob);
                    bsl::istream istream(&inbuf);

                    if (verbose) {
                        P_(i); P(k_BUFFER_SIZE);
                    }

                    ostream << 12345;
                    ostream.flush();

                    int j;
                    istream >> j;
                    LOOP_ASSERT(i, 12345 == j);
                    if (verbose) {
                        T_; P_(i); P(j);
                    }

                    istream.clear();
                    istream.seekg(0);

                    int k;
                    istream >> k;
                    LOOP_ASSERT(i, j == k);
                    if (verbose) {
                        T_; P_(i); P_(j); P(k);
                    }

                    istream.clear();
                    ostream.seekp(0);
                    istream.seekg(0);

                    bsl::string value;
                    ostream << 654321 << bsl::flush;
                    istream >> value;
                    LOOP_ASSERT(i, "654321" == value);

                    istream.clear();
                    ostream.seekp(0);
                    istream.seekg(0);

                    // Since we cannot truncate the streambuf, we must write at
                    // least as many bytes as already exist in the buffer.

                    int length = bsl::max(3 * (int)k_BUFFER_SIZE,
                                          blob.length());
                    const bsl::string HASHMARKS(length, '#');
                    bsl::string       result;
                    ostream << HASHMARKS << bsl::flush;
                    istream >> result;
                    LOOP_ASSERT(i, HASHMARKS == result);
                    if (verbose) {
                        T_; P_(i);
                        P_(HASHMARKS.length()); P(result.length());
                    }
                }
            }
        }
        ASSERT(0 <  ta.numAllocations());
        ASSERT(0 == ta.numBytesInUse());

      } break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }
Exemple #5
0
inline void debugprint(const bsl::string &s) {
    printf("\"%s\"", s.c_str());
    fflush(stdout);
}