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;
}
void TestReader::close() {
    if (d_prefixes) {
        d_prefixes->reset();
    }

    d_isOpen = false;
    d_encoding.clear();
    d_nodeDepth = 0;
    d_currentNode = 0;
}
void WordCountJob::operator()() {
  bool inWord = false;
  *d_result_p = 0;
  for (int i = 0; i < d_message.length(); ++i) {
    if (isspace(d_message[i])) {
       inWord = false;
    } else if (!inWord) {
       inWord = true;
       ++(*d_result_p);
    }
  }
}
// ACCESSORS
const char *TestReader::documentEncoding() const {
    return d_encoding.c_str();
}
Example #5
0
int main(int argc, char *argv[])
{
    int test = (argc > 1) ? bsl::atoi(argv[1]) : 0;

    verbose = (argc > 2);
    veryVerbose = (argc > 3);
    veryVeryVerbose = (argc > 4);
    veryVeryVeryVerbose = (argc > 5);

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

    switch (test) { case 0:
      case 7: {
        // --------------------------------------------------------------------
        // TESTING USAGE EXAMPLE 1
        //
        // Concerns:
        //   The usage example provided in the component header file must
        //   compile, link, and execute as shown.
        //
        // Plan:
        //   Incorporate the usage example from the header file into the test
        //   driver.  Make use of existing test apparatus by instantiating
        //   objects with a 'bslma::TestAllocator' object where applicable.
        //   Additionally, replace all calls to 'assert' in the usage example
        //   with calls to 'ASSERT'.  This now becomes the source, which is
        //   then "copied" back to the header file by reversing the above
        //   process.
        //
        // Testing:
        //   USAGE EXAMPLE 1
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Testing Usage Example" << endl
                 << "=====================" << endl;
        }

        const double RATE = 10;
        const double DURATION = 1.0;

        const bsl::string MESSAGE = "1234567890";
        const bsl::size_t MSGLEN  = MESSAGE.length();

        bsls::Stopwatch    timer;
        bsl::ostringstream oss;
        timer.start();
        heartbeat(oss, MESSAGE, RATE, DURATION - EPSILON);
        timer.stop();

        double       elapsed = timer.elapsedTime();

        // The elapsed time should not be off by more than 15 ms.

        LOOP_ASSERT(elapsed,
                         1.0 - EPSILON <= elapsed && elapsed <= 1.0 + EPSILON);

        // The number of executed events should not be off by more than one.

        LOOP_ASSERT(oss.str().length(),
                               RATE * DURATION * MSGLEN == oss.str().length());

        if (veryVerbose) {
            P_(RATE);    P(RATE * DURATION * (double) MESSAGE.length());
            P_(elapsed); P(oss.str().length());
        }
      }  break;
      case 6: {
        // --------------------------------------------------------------------
        // CONCERN: MULTI-THREADED TEST (LAG)
        //
        // Concerns:
        //   - That the turnstile lags when multiple threads call 'waitTurn' at
        //   lower than the configured rate.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 50.  Create
        //   multiple threads bound to a callback that calls 'waitTurn',
        //   increments an atomic counter, and then sleeps.  Start the threads.
        //   Join the threads, and verify that the value of the counter is
        //   less than the expected number of turns.
        //
        // Testing:
        //   Concern: Multi-Threaded Test (Lag)
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Concern: Multi-Threaded Test (Lag)" << endl
                 << "==================================" << endl;
        }

        /* TBD -- bind
        const bsls::TimeInterval OFFSET(1.0);        // turnstile start offset
        const double            RATE        = 50.0;
        const int               NUM_TURNS   = 50;
        const int               NUM_THREADS = 3;

        bsls::TimeInterval stopTime(bsls::SystemTime::nowRealtimeClock());
        stopTime.addMilliseconds(2 * OFFSET.totalMilliseconds());

        Obj        mX(RATE, OFFSET);
        const Obj& X = mX;

        bsl::vector<bslmt::ThreadUtil::Handle> handles;
        bsls::AtomicInt                        counter;
        bsls::TimeInterval                     sleepInterval(0.075);  // 75ms
        bslmt::Barrier                         barrier(NUM_THREADS + 1);
        handles.reserve(NUM_THREADS);

        ASSERT(10 < sleepInterval.totalMilliseconds());
            // Guarantee that the threads will sleep

        for (int i = 0; i < NUM_THREADS; ++i) {
            bslmt::ThreadUtil::Handle handle;
            ASSERT(0 == bslmt::ThreadUtil::create(&handle,
                                                 bdlf::BindUtil::bind(
                                                     &waitTurnAndSleepCallback,
                                                     &mX,
                                                     &counter,
                                                     &barrier,
                                                     sleepInterval,
                                                     stopTime)));
            handles.push_back(handle);
        }

        barrier.wait();

        // Cleanup threads
        for (int i = 0; i < (int) handles.size(); ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(handles[i]));
        }

        ASSERT(0         < X.lagTime());
        ASSERT(NUM_TURNS > counter);
        if (NUM_TURNS <= counter) {
            P_(NUM_TURNS); P(counter);
        }
        if (veryVerbose) {
            P_(sleepInterval); P_(NUM_TURNS); P(counter);
        }
        */
      }  break;
      case 5: {
        // --------------------------------------------------------------------
        // CONCERN: MULTI-THREADED TEST (NO LAG)
        //
        // Concerns:
        //   - That calling 'waitTurn' from multiple threads is thread-safe.
        //
        //   - That the turnstile does not lag when multiple threads call
        //     'waitTurn' at the configured rate.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 50.  Create
        //   multiple threads bound to a callback that calls 'waitTurn', and
        //   then increments an atomic counter.  Start the threads.  Join the
        //   threads, and verify that the value of the counter is at least the
        //   expected number of turns.
        //
        // Testing:
        //   Concern: Multi-Threaded Test (No Lag)
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Concern: Multi-Threaded Test (No Lag)" << endl
                 << "=====================================" << endl;
        }

        /* TBD -- bind
        const bsls::TimeInterval OFFSET(1.0);        // turnstile start offset
        const double            RATE        = 8;
        const int               NUM_TURNS   = 8;
        const int               NUM_THREADS = 3;

        bsls::TimeInterval stopTime(bsls::SystemTime::nowRealtimeClock());
        stopTime.addMilliseconds(2 * OFFSET.totalMilliseconds());

        Obj        mX(RATE, OFFSET);
        const Obj& X = mX;

        bsl::vector<bslmt::ThreadUtil::Handle> handles;
        bsls::AtomicInt                        counter;
        bslmt::Barrier                         barrier(NUM_THREADS + 1);
        handles.reserve(NUM_THREADS);
        for (int i = 0; i < NUM_THREADS; ++i) {
            bslmt::ThreadUtil::Handle handle;
            ASSERT(0 == bslmt::ThreadUtil::create(&handle,
                                                 bdlf::BindUtil::bind(
                                                     &waitTurnCallback,
                                                     &mX,
                                                     &counter,
                                                     &barrier,
                                                     stopTime)));
            handles.push_back(handle);
        }

        barrier.wait();

        // Cleanup threads
        for (int i = 0; i < (int) handles.size(); ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(handles[i]));
        }

        Int64 lt = X.lagTime();
        LOOP_ASSERT(lt, 0 == lt);
        LOOP_ASSERT(counter, NUM_TURNS <= counter);
        */
      }  break;
      case 4: {
        // --------------------------------------------------------------------
        // TESTING ALTERNATE CONSTRUCTORS
        //
        // Concerns:
        //   - That calling 'waitTurn' after constructing a turnstile with
        //     a specified start time blocks until that time.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 1, and a start
        //   time offset of 1 second; and a non-modifiable reference to 'mX'
        //   named 'X'.  Call 'waitTurn' on 'mX' and 'lagTime' on 'X'.  Verify
        //   that the result of both calls is positive, indicating that the
        //   caller is not lagging, and that some wait time is incurred.
        //   Verify that the wait time is within 10ms of the expected maximum
        //   wait time.
        //
        // Testing:
        //   bslmt::Turnstile(
        //       double                   rate,
        //       const bsls::TimeInterval& startTime = bsls::TimeInterval(0));
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Testing Alternate Constructors" << endl
                 << "==============================" << endl;
        }

        const double            RATE = 1.0;
        const bsls::TimeInterval OFFSET(1.0); // turnstile start offset (1 sec)

        const double WT   = 1.0 / RATE;    // max wait time for each turn
        const Int64  WTUB =
         static_cast<Int64>(k_USPS * (WT + EPSILON));  // upper bound wait time
        const Int64  WTLB =
         static_cast<Int64>(k_USPS * (WT - EPSILON));  // lower bound wait time

        Obj        mX(RATE, OFFSET);
        const Obj& X = mX;

        Int64 lt =  X.lagTime();
        Int64 wt = mX.waitTurn();
        ASSERT(0 == lt);  // not lagging since start time is offset
        ASSERT(0 <  wt);  // first turn cannot be taken immediately
        ASSERT(WTLB <= wt && wt <= WTUB);

        if (veryVerbose) {
            P_(WTLB); P_(WTUB); P_(wt); P(lt);
        }

      }  break;
      case 3: {
        // --------------------------------------------------------------------
        // TESTING FUNCTION 'reset'
        //
        // Concerns:
        //   - That the next turn may be taken immediately after calling
        //     'reset'.
        //
        //   - That 'reset' does not interrupt threads blocked on 'waitTurn'.
        //
        //   - That calling 'waitTurn' after resetting a turnstile with
        //     a specified start time blocks until that time.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 1, and a
        //   non-modifiable reference to 'mX' named 'X'.  Call 'waitTurn' on
        //   'mX' and 'lagTime' on 'X' to establish that the caller waits on
        //   the turnstile and that the caller is not lagging.  Then, call
        //   'reset' with the same rate.  Call 'waitTurn' on 'mX', and verify
        //   that the result is 0.  Sleep for twice the maximum wait time, and
        //   call 'waitTurn' and 'lagTime' again to establish that the caller
        //   is lagging.  Then, call 'reset' again with the same rate.  Verify
        //   that the result of 'waitTurn' is again 0.  Finally, call 'reset'
        //   with the same rate and an offset of 1 second.  Call 'waitTime' on
        //   'mX' and 'lagTime' on 'X'.  Verify that 'waitTime' returns a
        //   positive value, and that the caller is not lagging.
        //
        // Testing:
        //   void reset(
        //      double                   rate,
        //      const bsls::TimeInterval& startTime = bsls::TimeInterval(0));
        // --------------------------------------------------------------------

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

        const double            RATE = 1.0;
        const bsls::TimeInterval OFFSET(1.0); // turnstile reset offset (1 sec)

        Obj        mX(RATE);
        const Obj& X = mX;

        ASSERT(0 <=  X.lagTime());   // (likely) lagging on the first turn
        ASSERT(0 == mX.waitTurn());  // first turn can be taken immediately
        ASSERT(0 ==  X.lagTime());   // not lagging
        ASSERT(0 <  mX.waitTurn());  // second turn incurs wait
        ASSERT(0 ==  X.lagTime());   // not lagging

        mX.reset(RATE);
        ASSERT(0 <=  X.lagTime());   // (likely) lagging after 'reset'
        ASSERT(0 == mX.waitTurn());  // first turn can be taken immediately
        ASSERT(0 ==  X.lagTime());   // not lagging
        ASSERT(0 <  mX.waitTurn());  // second turn incurs wait
        ASSERT(0 ==  X.lagTime());   // not lagging

        bslmt::ThreadUtil::microSleep(3 * k_USPS);
        ASSERT(0 == mX.waitTurn());
        ASSERT(0 <   X.lagTime());   // lagging after sleep

        mX.reset(RATE);
        ASSERT(0 <=  X.lagTime());   // (likely) lagging after 'reset'
        ASSERT(0 == mX.waitTurn());  // first turn can be taken immediately
        ASSERT(0 ==  X.lagTime());   // not lagging
        ASSERT(0 <  mX.waitTurn());  // second turn incurs wait
        ASSERT(0 ==  X.lagTime());   // not lagging

        mX.reset(RATE, OFFSET);
        ASSERT(0 ==  X.lagTime());   // not lagging after 'reset'
        ASSERT(0 <  mX.waitTurn());  // first turn incurs wait
        ASSERT(0 ==  X.lagTime());   // not lagging
        ASSERT(0 <  mX.waitTurn());  // second turn incurs wait
        ASSERT(0 ==  X.lagTime());   // not lagging
      }  break;
      case 2: {
        // --------------------------------------------------------------------
        // TESTING FUNCTION 'waitTurn'
        //
        // Concerns:
        //   - That 'waitTurn' returns a positive value that is within a small
        //     epsilon of the expected wait time when waiting is required.
        //
        //   - That 'lagTime' returns 0 when turns are taken at or above the
        //     specified rate.
        //
        //   - That 'waitTurn' returns 0 when turns are taken more slowly than
        //     the specified rate.
        //
        //   - That 'lagTime' returns a positive value when turns are taken
        //     more slowly than the specified rate.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 10.0, and a
        //   non-modifiable reference to 'mX' named 'X'.  In a loop, call
        //   'waitTurn' on 'mX' and 'lagTime' on 'X'.  Verify that the result
        //   of 'waitTime' is within 10ms of the expected maximum wait time,
        //   and that the result of 'lagTime' is 0.  Then, sleep for
        //   twice the maximum wait time, and very that the result of
        //   'waitTime' is 0, and the result of 'lagTime' is positive.
        //
        // Testing:
        //   bsls::Types::Int64 waitTurn();
        //   bsls::Types::Int64 lagTime() const;
        // --------------------------------------------------------------------

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

        // Turns are taken at or above the specified rate

        const double RATE = 5.0;
        const double WT   = 1.0 / RATE;  // max wait time for each turn
        const Int64  WTUB = k_USPS * (WT + EPSILON);  // upper bound wait time
        const Int64  WTLB = k_USPS * (WT - EPSILON);  // lower bound wait time

        if (verbose) {
            P_(RATE)   P_(WT)  P_(WTUB)  P(WTLB);
        }

        Obj        mX(RATE);
        const Obj& X = mX;

        int numTurns = RATE;

        ASSERT(0 <=  X.lagTime());   // (likely) lagging on the first turn
        ASSERT(0 == mX.waitTurn());  // first turn can be taken immediately

        // First, burn a turn.  This incurs a wait, but a smaller wait than the
        // maximum (since some processing has already been done).  After taking
        // two turns, subsequent calls to 'waitTurn' should incur (close to)
        // the maximum wait time.
        mX.waitTurn();
        do {
            Int64 wt = mX.waitTurn();
            Int64 lt =  X.lagTime();
            LOOP3_ASSERT(WTLB, WTUB, wt, WTLB <= wt && wt <= WTUB);
            ASSERT(0 == lt);
            if (veryVerbose) {
                P_(WTLB); P_(WTUB); P_(wt); P(lt);
            }
        } while (--numTurns);

        // Turns are taken more slowly than the specified rate

        // 'X.lagTime()' does not report negative values, but suppose it did.
        // Call 'epsA' the amount of time we've spent doing stuff since the
        // last 'waitTurn'.  Then 'X.lagTime() == - k_USPS * WT + epsA' at this
        // point.

        // Wait 2.25 times the period time

        int sleepTime = (int) (2.5 * k_USPS * WT);
        bslmt::ThreadUtil::microSleep(sleepTime);

        // At this point.  'X.lagTime() == 1.5 * k_USPS * WT + epsA'.  Take one
        // turn.

        ASSERT(0 == mX.waitTurn());

        // Now, 'X.lagTime() == 0.5 * k_USPS * WT + epsA'.  Note that we can't
        // rely on system clocks having a small enough resolution to notice
        // 'epsA'.  Verify that lagTime is positive.

        int lagTime = X.lagTime();
        LOOP_ASSERT(lagTime, 0 < lagTime);

        if (verbose) { P_(sleepTime) P(lagTime); }
      }  break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST
        //
        // Concerns:
        //   Exercise the basic functionality of the 'bslmt::Turnstile' class.
        //   Ensure that a turnstile can be instantiated and destroyed.  Also
        //   exercise the primary manipulators and accessors.
        //
        // Plan:
        //   Create a 'bslmt::Turnstile', 'mX', with a rate of 1, and a
        //   non-modifiable reference to 'mX' named 'X'.  Call 'waitTurn' on
        //   'mX' and 'lagTime' on 'X'.  Destroy 'mX'.
        //
        // Testing:
        //   Exercise basic functionality
        // --------------------------------------------------------------------

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

        const double RATE = 1.0;

        Obj        mX(RATE);
        const Obj& X = mX;

        ASSERT(0 <=  X.lagTime());   // (likely) lagging on the first turn
        ASSERT(0 == mX.waitTurn());  // first turn can be taken immediately

      }  break;
      case -1: {
        // --------------------------------------------------------------------
        // COMPARISON OF SLEEP TO TURNSTILE
        //
        // Concerns:
        //   Compare the difference in elapsed time between 'sleep' and
        //   'bslmt::Turnstile' implementations of the heartbeat usage example
        //   at various rates.
        //
        // Plan:
        //   Call two functions, 'processWithTurnstile' and 'processWithSleep',
        //   with various rates and durations.  Compare the elapsed time
        //   returned by these functions to the expected elapsed time.  Verify
        //   that the drift resulting from calling "sleep" in the
        //   'processWithSleep' function results in a greater difference from
        //   the expected time that the elapsed time returned by the
        //   'bslmt::Turnstile' implementation.
        //
        // Testing:
        //   Comparison of 'sleep' to 'bslmt::Turnstile'
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "Comparison of 'sleep' to 'bslmt::Turnstile'" << endl
                 << "==========================================" << endl;
        }

        const struct {
            int    d_line;        // test line number
            double d_rate;        // number of turns per second
            double d_duration;    // duration of test in seconds
        } DATA[] = {
            //Line  Rate  Duration
            //----  ----  --------
            { L_,      2,        1, },
            { L_,      4,        1, },
            { L_,      8,        1, },
            { L_,     10,        1, },
            { L_,     10,        2, },
            { L_,     10,        4, },
            { L_,     10,        8, },
            { L_,    100,        1, },
            { L_,    100,        2, },
            { L_,    100,        4, },
            { L_,    100,        8, },
            { L_,    500,        1, },
            { L_,    500,        2, },
            { L_,    500,        4, },
            { L_,    500,        8, },
            { L_,   1000,        1, },
            { L_,   1000,        2, },
            { L_,   1000,        4, },
            { L_,   1000,        8, },
        };
        const int DATA_SIZE = static_cast<int>(sizeof DATA / sizeof *DATA);

        for (int i = 0; i < DATA_SIZE; ++i) {
            int    LINE     = DATA[i].d_line;
            double RATE     = DATA[i].d_rate;
            double DURATION = DATA[i].d_duration;

            double elapsed1 = 0.0;
            double elapsed2 = 0.0;

            processorWithTurnstile(RATE, DURATION, &elapsed1);
            processorWithSleep    (RATE, DURATION, &elapsed2);

            bsl::printf("Line = %d, Rate = %f, Duration = %f\n"
                        "    elapsed1 = %.6f\n"
                        "    elapsed2 = %.6f\n\n"
                        , LINE, RATE, DURATION
                        , elapsed1, elapsed2);

            LOOP3_ASSERT(LINE, RATE, DURATION, elapsed1 <= elapsed2);
        }
      }  break;
      case -2: {
        // --------------------------------------------------------------------
        // SYSTEM CLOCK CHANGES DO NOT CAUSE HANGS
        //
        // Concerns:
        //: 1 Before recent changes to this component, a system clock change
        //:   could cause the 'bslmt::Turnstile' to appear to hang.
        //
        // Plan:
        //: 1 Create a 'bslmt::Turnstile' which prints a message once a second,
        //:   externally change the time, externally verify the messages do
        //:   not stop printing.
        //
        // Testing:
        //   'bslmt::Turnstile' behavior is immune to system clock changes.
        // --------------------------------------------------------------------

        if (verbose) {
            cout << "SYSTEM CLOCK CHANGES DO NOT CAUSE HANGS" << endl
                 << "=======================================" << endl;
        }

        cout << endl
             << endl << "Modify your current system time."
             << endl
             << endl << "A message will be printed every second and if the"
             << endl << "messages stop printing before iteration 300 while"
             << endl << "you are changing the system time there is an issue."
             << endl << "You may use CNTRL-C to exit this test at any time."
             << endl << "The test will begin in three seconds; do not change"
             << endl << "the system time until after you see the first printed"
             << endl << "message."
             << endl;

        bslmt::ThreadUtil::microSleep(3 * k_USPS);

        bslmt::Turnstile turnstile(1.0);
        unsigned count = 0;
        while (count < 300) {
            turnstile.waitTurn();
            ++count;
            cout << "turnstile iteration: " << count << endl;
        }
      }  break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "."
             << endl;
    }
    return testStatus;
}
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;
}
Example #7
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;
      }
    }
Example #8
0
inline void debugprint(const bsl::string &s) {
    printf("\"%s\"", s.c_str());
    fflush(stdout);
}