Changeset 1376

Show
Ignore:
Timestamp:
08/12/08 10:30:11 (5 months ago)
Author:
jtv
Message:

Converted more tests to test framework; further framework improvements.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ChangeLog

    r1375 r1376  
     12008-08-12  Jeroen T. Vermeulen <jtv@xs4all.nl> 
     2 test/test011.cxx, test/test012.cxx, test/test013.cxx, test/test014.cxx,  
     3 test/test015.cxx, test/test016.cxx, test/test_helpers.hxx: 
     4  - Converted to test framework 
     5  - Replaced assertions with test helpers 
     6  - Testing string conversions for result tuples & iterators 
     7  - Simplified testing string conversion for result 
    182008-08-10  Jeroen T. Vermeulen <jtv@xs4all.nl> 
    29 include/pqxx/connection.hxx, src/connection.cxx: 
  • trunk/test/test011.cxx

    r1284 r1376  
    77#include <pqxx/result> 
    88 
     9#include "test_helpers.hxx" 
     10 
    911using namespace PGSTD; 
    1012using namespace pqxx; 
     
    1214 
    1315// Test program for libpqxx.  Query a table and report its metadata. 
    14 // 
    15 // Usage: test011 [connect-string] [table] 
    16 // 
    17 // Where table is the table to be queried; if none is given, pg_tables is 
    18 // queried by default. 
    19 // 
    20 // The connect-string is a set of connection options in Postgresql's 
    21 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    22 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    23 // backend running on host foo.bar.net, logging in as user smith. 
    24 int main(int argc, char *argv[]) 
     16namespace 
    2517{ 
    26   try 
     18void test_011(connection_base &, transaction_base &T) 
     19
     20  const string Table = "pg_tables"; 
     21 
     22  result R( T.exec("SELECT * FROM " + Table) ); 
     23 
     24  // Print column names 
     25  for (result::tuple::size_type c = 0; c < R.columns(); ++c) 
    2726  { 
    28     const string Table = ((argc >= 3) ? argv[2] : "pg_tables"); 
     27    string N = R.column_name(c); 
     28    cout << c << ":\t" << N << endl; 
     29    PQXX_CHECK_EQUAL(R.column_number(N), c, "Inconsistent column numbers."); 
     30  } 
    2931 
    30     connection C(argv[1]); 
    31     work T(C, "test11"); 
     32  // If there are rows in R, compare their metadata to R's. 
     33  if (!R.empty()) 
     34  { 
     35    PQXX_CHECK_EQUAL(R[0].rownumber(), 0u, "Row 0 has wrong number."); 
    3236 
    33     result R( T.exec("SELECT * FROM " + Table) ); 
     37    if (R.size() < 2) 
     38      cout << "(Only one row in table.)" << endl; 
     39    else 
     40      PQXX_CHECK_EQUAL(R[1].rownumber(), 1u, "Row 1 has wrong number."); 
    3441 
    35     // Print column names 
    36     for (result::tuple::size_type c = 0; c < R.columns(); ++c) 
     42    // Test tuple::swap() 
     43    const result::tuple T1(R[0]), T2(R[1]); 
     44    PQXX_CHECK_NOT_EQUAL(T1, T2, "Values are identical--can't test swap()."); 
     45    result::tuple T1s(T1), T2s(T2); 
     46    PQXX_CHECK_EQUAL(T1s, T1, "Tuple copy-construction incorrect."); 
     47    PQXX_CHECK_EQUAL(T2s, T2, "Tuple copy-construction inconsistently wrong."); 
     48    T1s.swap(T2s); 
     49    PQXX_CHECK_NOT_EQUAL(T1s, T1, "Tuple swap doesn't work."); 
     50    PQXX_CHECK_NOT_EQUAL(T2s, T2, "Tuple swap inconsistently wrong."); 
     51    PQXX_CHECK_EQUAL(T2s, T1, "Tuple swap is asymmetric."); 
     52    PQXX_CHECK_EQUAL(T1s, T2, "Tuple swap is inconsistently asymmetric."); 
     53 
     54    for (result::tuple::size_type c = 0; c < R[0].size(); ++c) 
    3755    { 
    38       string N= R.column_name(c); 
    39       cout << c << ":\t" << N << endl; 
    40       if (R.column_number(N) != c) 
    41         throw logic_error("Expected column '" + N + 
    42                           "' to be no. " + to_string(c) + ", " 
    43                           "but it was no. " + to_string(R.column_number(N))); 
    44     } 
     56      string N = R.column_name(c); 
    4557 
    46     // If there are rows in R, compare their metadata to R's. 
    47     if (!R.empty()) 
    48     { 
    49       if (R[0].rownumber() != 0) 
    50         throw logic_error("Row 0 said it was row " + R[0].rownumber()); 
     58      PQXX_CHECK_EQUAL( 
     59        string(R[0].at(c).c_str()), 
     60        R[0].at(N).c_str(), 
     61        "Field by name != field by number."); 
    5162 
    52       if (R.size() < 2) 
    53         cout << "(Only one row in table.)" << endl; 
    54       else if (R[1].rownumber() != 1) 
    55         throw logic_error("Row 1 said it was row " + R[1].rownumber()); 
     63      PQXX_CHECK_EQUAL( 
     64        string(R[0][c].c_str()), 
     65        R[0][N].c_str(), 
     66       "at() is inconsistent with operator[]."); 
    5667 
    57       // Test tuple::swap() 
    58       const result::tuple T1(R[0]), T2(R[1]); 
    59       if (T2 == T1) 
    60         throw runtime_error("Values are identical, can't test swap()!"); 
    61       result::tuple T1s(T1), T2s(T2); 
    62       if (T1s != T1 || !(T2s == T2)) 
    63         throw logic_error("Tuple copy-construction incorrect"); 
    64       T1s.swap(T2s); 
    65       if (T1s == T1 || !(T2s != T2)) 
    66         throw logic_error("Tuple swap doesn't work"); 
    67       if (T2s != T1 || !(T1s == T2)) 
    68         throw logic_error("Tuple swap is asymmetric"); 
     68      PQXX_CHECK_EQUAL(R[0][c].name(), N, "Field names are inconsistent."); 
    6969 
    70       for (result::tuple::size_type c = 0; c < R[0].size(); ++c) 
    71       { 
    72         string N = R.column_name(c); 
    73  
    74         if (string(R[0].at(c).c_str()) != R[0].at(N).c_str()) 
    75           throw logic_error("Field " + to_string(c) + " contains " 
    76                             "'" + R[0].at(c).c_str() + "'; " 
    77                             "field '" + N + "' " 
    78                             "contains '" + R[0].at(N).c_str() + "'"); 
    79         if (string(R[0][c].c_str()) != R[0][N].c_str()) 
    80           throw logic_error("Field " + to_string(c) + " ('" + N + "'): " 
    81                             "at() inconsistent with operator[]!"); 
    82  
    83         if (R[0][c].name() != N) 
    84           throw logic_error("Field " + to_string(c) + " " 
    85                             "called '" + N + "' by result, " 
    86                             "but '" + R[0][c].name() + "' by Field object"); 
    87  
    88         if (size_t(R[0][c].size()) != strlen(R[0][c].c_str())) 
    89           throw logic_error("Field '" + N + "' " 
    90                             "says its length is " + to_string(R[0][c].size()) + 
    91                             ", " 
    92                             "but its value is '" + R[0][c].c_str() + "' " 
    93                             "(" + to_string(strlen(R[0][c].c_str())) + " " 
    94                             "chars)"); 
    95       } 
    96     } 
    97     else 
    98     { 
    99       cout << "(Table is empty.)" << endl; 
     70      PQXX_CHECK_EQUAL( 
     71        size_t(R[0][c].size()), 
     72        strlen(R[0][c].c_str()), 
     73        "Field size is not what we expected."); 
    10074    } 
    10175  } 
    102   catch (const sql_error &e) 
     76  else 
    10377  { 
    104     // If we're interested in the text of a failed query, we can write separate 
    105     // exception handling code for this type of exception 
    106     cerr << "SQL error: " << e.what() << endl 
    107          << "Query was: '" << e.query() << "'" << endl; 
    108     return 1; 
     78    cout << "(Table is empty.)" << endl; 
    10979  } 
    110   catch (const exception &e) 
    111   { 
    112     // All exceptions thrown by libpqxx are derived from std::exception 
    113     cerr << "Exception: " << e.what() << endl; 
    114     return 2; 
    115   } 
    116   catch (...) 
    117   { 
    118     // This is really unexpected (see above) 
    119     cerr << "Unhandled exception" << endl; 
    120     return 100; 
    121   } 
     80
     81} // namespace 
    12282 
    123   return 0; 
    124 
    125  
     83PQXX_REGISTER_TEST(test_011) 
  • trunk/test/test012.cxx

    r1138 r1376  
    77#include <pqxx/result> 
    88 
     9#include "test_helpers.hxx" 
     10 
    911using namespace PGSTD; 
    1012using namespace pqxx; 
     
    1315// Test program for libpqxx.  See which fields in a query are null, and figure 
    1416// out whether any fields are lexicographically sorted. 
    15 // 
    16 // Usage: test012 [connect-string] [table] 
    17 // 
    18 // Where table is the table to be queried; if none is given, pg_tables is 
    19 // queried by default. 
    20 // 
    21 // The connect-string is a set of connection options in Postgresql's 
    22 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    23 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    24 // backend running on host foo.bar.net, logging in as user smith. 
    2517 
    2618namespace 
     
    3224  for (typename VEC::iterator i = V.begin(); i != V.end(); ++i) *i = val; 
    3325} 
     26 
     27void test_012(connection_base &C, transaction_base &orgT) 
     28{ 
     29  orgT.abort(); 
     30 
     31  const string Table = "pg_tables"; 
     32 
     33  // Tell C we won't be needing it for a while (not true, but let's pretend) 
     34  C.deactivate(); 
     35 
     36  // Now set up some data structures 
     37  vector<int> NullFields;               // Maps column to no. of null fields 
     38  vector<bool> SortedUp, SortedDown;    // Does column appear to be sorted? 
     39 
     40  // ...And reactivate C (not really needed, but it sounds more polite) 
     41  C.activate(); 
     42 
     43  work T(C, "test12"); 
     44 
     45  result R( T.exec("SELECT * FROM " + Table) ); 
     46 
     47  InitVector(NullFields, R.columns(), 0); 
     48  InitVector(SortedUp, R.columns(), true); 
     49  InitVector(SortedDown, R.columns(), true); 
     50 
     51  for (result::const_iterator i = R.begin(); i != R.end(); i++) 
     52  { 
     53    PQXX_CHECK_EQUAL( 
     54        (*i).rownumber(), 
     55        i->rownumber(), 
     56        "Inconsistent row numbers for operator*() and operator->()."); 
     57 
     58    PQXX_CHECK_EQUAL(i->size(), R.columns(), "Inconsistent row size."); 
     59 
     60    // Look for null fields 
     61    for (result::tuple::size_type f=0; f<i->size(); ++f) 
     62    { 
     63      NullFields[f] += i.at(f).is_null(); 
     64 
     65      string A, B; 
     66      PQXX_CHECK_EQUAL( 
     67        i[f].to(A), 
     68        i[f].to(B, string("")), 
     69        "Variants of to() disagree on nullness."); 
     70 
     71      PQXX_CHECK_EQUAL(A, B, "Inconsistent field contents."); 
     72    } 
     73 
     74    // Compare fields to those of preceding row 
     75    if (i != R.begin()) 
     76    { 
     77      const result::const_iterator j = i - 1; 
     78 
     79      // First perform some sanity checks on j vs. i and how libpqxx handles 
     80      // their interrelationship... 
     81      PQXX_CHECK_EQUAL(i - j, 1, "Iterator is wrong distance from successor."); 
     82 
     83      PQXX_CHECK(!(j == i), "Iterator equals its successor."); 
     84      PQXX_CHECK(j != i, "Iterator inequality is inconsistent."); 
     85      PQXX_CHECK(!(j >= i), "Iterator doesn't come before its successor."); 
     86      PQXX_CHECK(!(j > i), "Iterator is preceded by its successor."); 
     87      PQXX_CHECK(!(i <= j), "Iterator doesn't come after its predecessor."); 
     88      PQXX_CHECK(!(i < j), "Iterator is succeded by its predecessor."); 
     89      PQXX_CHECK(j <= i, "operator<=() doesn't mirror operator>=()."); 
     90      PQXX_CHECK(j < i, "operator<() doesn't mirror operator>()."); 
     91 
     92      PQXX_CHECK_EQUAL(1 + j, i, "Adding 1 doesn't reach successor."); 
     93 
     94      result::const_iterator k(i); 
     95      PQXX_CHECK_EQUAL(k--, i, "Post-increment returns wrong iterator."); 
     96      PQXX_CHECK_EQUAL(k, j, "Bad iterator position after post-increment."); 
     97 
     98      result::const_iterator l(i); 
     99      PQXX_CHECK_EQUAL(--l, j, "Pre-increment returns wrong iterator."); 
     100      PQXX_CHECK_EQUAL(l, j, "Pre-increment sets wrong iterator position."); 
     101 
     102      PQXX_CHECK_EQUAL(k += 1, i, "Wrong return value from +=."); 
     103      PQXX_CHECK_EQUAL(k, i, "Bad iterator position after +=."); 
     104 
     105      PQXX_CHECK_EQUAL(k -= 1, j, "Wrong return value from -=."); 
     106      PQXX_CHECK_EQUAL(k, j, "Bad iterator position after -=."); 
     107 
     108      // ...Now let's do meaningful stuff with j, such as finding out which 
     109      // fields may be sorted.  Don't do anything fancy like trying to 
     110      // detect numbers and comparing them as such, just compare them as 
     111      // simple strings. 
     112      for (result::tuple::size_type f = 0; f < R.columns(); ++f) 
     113      { 
     114        if (!j[f].is_null()) 
     115        { 
     116          const bool U = SortedUp[f], 
     117                     D = SortedDown[f]; 
     118 
     119          SortedUp[f] = U & (string(j[f].c_str()) <= string(i[f].c_str())); 
     120          SortedDown[f] = D & (string(j[f].c_str()) >= string(i[f].c_str())); 
     121        } 
     122      } 
     123    } 
     124  } 
     125 
     126  // Now report on what we've found 
     127  cout << "Read " << to_string(R.size()) << " rows." << endl; 
     128  cout << "Field \t Field Name\t Nulls\t Sorted" << endl; 
     129 
     130  for (result::tuple::size_type f = 0; f < R.columns(); ++f) 
     131  { 
     132    cout << to_string(f) << ":\t" 
     133         << R.column_name(f) << '\t' 
     134         << NullFields[f] << '\t' 
     135         << (SortedUp[f] ? 
     136                (SortedDown[f] ? "equal" : "up" ) : 
     137                (SortedDown[f] ? "down" : "no" ) ) 
     138         << endl; 
     139 
     140    PQXX_CHECK( 
     141        NullFields[f] <= int(R.size()), 
     142        "Found more nulls than there were rows."); 
     143  } 
     144} 
    34145} // namespace 
    35146 
    36 int main(int argc, char *argv[]) 
    37 
    38   try 
    39   { 
    40     const string Table = ((argc >= 3) ? argv[2] : "pg_tables"); 
    41  
    42     connection C(argv[1]); 
    43  
    44     // Tell C we won't be needing it for a while (not true, but let's pretend) 
    45     C.deactivate(); 
    46  
    47     // Now set up some data structures 
    48     vector<int> NullFields;             // Maps column to no. of null fields 
    49     vector<bool> SortedUp, SortedDown;  // Does column appear to be sorted? 
    50  
    51     // ...And reactivate C (not really needed, but it sounds more polite) 
    52     C.activate(); 
    53  
    54     work T(C, "test12"); 
    55  
    56     result R( T.exec("SELECT * FROM " + Table) ); 
    57  
    58     InitVector(NullFields, R.columns(), 0); 
    59     InitVector(SortedUp, R.columns(), true); 
    60     InitVector(SortedDown, R.columns(), true); 
    61  
    62     for (result::const_iterator i = R.begin(); i != R.end(); i++) 
    63     { 
    64       if ((*i).rownumber() != i->rownumber()) 
    65         throw logic_error("Inconsistent rows: operator*() says " + 
    66                           to_string((*i).rownumber()) + ", " 
    67                           "operator->() says " + 
    68                           to_string(i->rownumber())); 
    69  
    70       if (i->size() != R.columns()) 
    71         throw logic_error("Row claims to have " + to_string(i->size()) + " " 
    72                           "fields, but result claims to have " + 
    73                           to_string(R.columns()) + " columns!"); 
    74  
    75       // Look for null fields 
    76       for (result::tuple::size_type f=0; f<i->size(); ++f) 
    77       { 
    78         NullFields[f] += i.at(f).is_null(); 
    79  
    80         string A, B; 
    81         if (i[f].to(A) != i[f].to(B, string(""))) 
    82           throw logic_error("Variants of to() disagree on nullness!"); 
    83  
    84         if (A != B) 
    85           throw logic_error("Field is '" + A + "' according to one to(), " 
    86                             "but '" + B + "' to the other!"); 
    87       } 
    88  
    89       // Compare fields to those of preceding row 
    90       if (i != R.begin()) 
    91       { 
    92         const result::const_iterator j = i - 1; 
    93  
    94         // First perform some sanity checks on j vs. i and how libpqxx handles 
    95         // their interrelationship... 
    96         if ((i - j) != 1) 
    97           throw logic_error("Difference between iterator and successor is " + 
    98                             to_string(j-i)); 
    99  
    100         if ((j == i) || !(j != i) || 
    101             (j >= i) || (j > i) || 
    102             (i <= j) || (i < j) || 
    103             !(j <= i) || !(j < i)) 
    104           throw logic_error("Something wrong in comparison between iterator " 
    105                             "and its successor!"); 
    106  
    107         if ((1 + j) != i) 
    108           throw logic_error("Adding iterator's predecessor to 1 " 
    109                             "doesn't bring us back to original iterator!"); 
    110  
    111         result::const_iterator k(i); 
    112         if ((k-- != i) || (k != j)) 
    113           throw logic_error("Something wrong with increment operator!"); 
    114  
    115         result::const_iterator l(i); 
    116         if ((--l != j) || (l != j)) 
    117           throw logic_error("Something wrong with pre-increment operator!"); 
    118  
    119         if ((k += 1) != i) 
    120           throw logic_error("Something wrong with += operator!"); 
    121  
    122         if ((k -= 1) != j) 
    123           throw logic_error("Something wrong with -= operator!"); 
    124  
    125         // ...Now let's do meaningful stuff with j, such as finding out which 
    126         // fields may be sorted.  Don't do anything fancy like trying to 
    127         // detect numbers and comparing them as such, just compare them as 
    128         // simple strings. 
    129         for (result::tuple::size_type f = 0; f < R.columns(); ++f) 
    130         { 
    131           if (!j[f].is_null()) 
    132           { 
    133             const bool U = SortedUp[f], 
    134                        D = SortedDown[f]; 
    135  
    136             SortedUp[f] = U & (string(j[f].c_str()) <= string(i[f].c_str())); 
    137             SortedDown[f] = D & (string(j[f].c_str()) >= string(i[f].c_str())); 
    138           } 
    139         } 
    140       } 
    141     } 
    142  
    143     // Now report on what we've found 
    144     cout << "Read " << to_string(R.size()) << " rows." << endl; 
    145     cout << "Field \t Field Name\t Nulls\t Sorted" << endl; 
    146  
    147     for (result::tuple::size_type f = 0; f < R.columns(); ++f) 
    148     { 
    149       cout << to_string(f) << ":\t" 
    150            << R.column_name(f) << '\t' 
    151            << NullFields[f] << '\t' 
    152            << (SortedUp[f] ? 
    153                 (SortedDown[f] ? "equal" : "up" ) : 
    154                 (SortedDown[f] ? "down" : "no" ) ) 
    155            << endl; 
    156  
    157       if (NullFields[f] > int(R.size())) 
    158         throw logic_error("Found more nulls than there were rows!"); 
    159     } 
    160   } 
    161   catch (const sql_error &e) 
    162   { 
    163     // If we're interested in the text of a failed query, we can write separate 
    164     // exception handling code for this type of exception 
    165     cerr << "SQL error: " << e.what() << endl 
    166          << "Query was: '" << e.query() << "'" << endl; 
    167     return 1; 
    168   } 
    169   catch (const exception &e) 
    170   { 
    171     // All exceptions thrown by libpqxx are derived from std::exception 
    172     cerr << "Exception: " << e.what() << endl; 
    173     return 2; 
    174   } 
    175   catch (...) 
    176   { 
    177     // This is really unexpected (see above) 
    178     cerr << "Unhandled exception" << endl; 
    179     return 100; 
    180   } 
    181  
    182   return 0; 
    183 
    184  
     147PQXX_REGISTER_TEST_T(test_012, nontransaction) 
  • trunk/test/test013.cxx

    r1175 r1376  
    99#include <pqxx/result> 
    1010 
     11#include "test_helpers.hxx" 
     12 
    1113using namespace PGSTD; 
    1214using namespace pqxx; 
     
    1517// Test program for libpqxx.  Verify abort behaviour of transactor. 
    1618// 
    17 // Usage: test013 [connect-string] [table] 
    18 // 
    19 // Where connect-string is a set of connection options in Postgresql's 
    20 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    21 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    22 // backend running on host foo.bar.net, logging in as user smith. 
    23 // 
    2419// The program will attempt to add an entry to a table called "pqxxevents", 
    2520// with a key column called "year"--and then abort the change. 
     
    2722// Note for the superstitious: the numbering for this test program is pure 
    2823// coincidence. 
    29  
    30  
    3124namespace 
    3225{ 
     
    6053 
    6154 
    62  
    6355class FailedInsert : public transactor<> 
    6456{ 
     
    7769                     "'yawn')") ); 
    7870 
    79     assert(R.affected_rows() == 1); 
     71    PQXX_CHECK_EQUAL(R.affected_rows(), 1u, "Bad affected_rows()."); 
    8072    cout << "Inserted row with oid " << R.inserted_oid() << endl; 
    8173 
     
    10092 
    10193 
     94void test_013(connection_base &C, transaction_base &T) 
     95{ 
     96  T.abort(); 
     97 
     98  const string Table = "pqxxevents"; 
     99 
     100  pair<int,int> Before; 
     101  C.perform(CountEvents(Table, Before)); 
     102  PQXX_CHECK_EQUAL( 
     103        Before.second, 
     104        0, 
     105        "Already have event for " + to_string(BoringYear) + "--can't test."); 
     106 
     107  const FailedInsert DoomedTransaction(Table); 
     108  disable_noticer d(C); 
     109  PQXX_CHECK_THROWS( 
     110        C.perform(DoomedTransaction), 
     111        runtime_error, 
     112        "Failing transactor failed to throw correct exception."); 
     113 
     114  pair<int,int> After; 
     115  C.perform(CountEvents(Table, After)); 
     116 
     117  PQXX_CHECK_EQUAL( 
     118        After.first, 
     119        Before.first, 
     120        "abort() didn't reset event count."); 
     121 
     122  PQXX_CHECK_EQUAL( 
     123        After.second, 
     124        Before.second, 
     125        "abort() didn't reset event count for " + to_string(BoringYear)); 
     126} 
     127 
    102128} // namespace 
    103129 
    104  
    105 int main(int argc, char *argv[]) 
    106 
    107   try 
    108   { 
    109     connection C(argv[1]); 
    110  
    111     const string Table = ((argc > 2) ? argv[2] : "pqxxevents"); 
    112  
    113     pair<int,int> Before; 
    114     C.perform(CountEvents(Table, Before)); 
    115     if (Before.second) 
    116       throw runtime_error("Table already has an event for " + 
    117                           to_string(BoringYear) + ", " 
    118                           "cannot run."); 
    119  
    120     const FailedInsert DoomedTransaction(Table); 
    121  
    122     try 
    123     { 
    124       disable_noticer d(C); 
    125       C.perform(DoomedTransaction); 
    126     } 
    127     catch (const exception &e) 
    128     { 
    129       cout << "(Expected) Doomed transaction failed: " << e.what() << endl; 
    130     } 
    131  
    132     pair<int,int> After; 
    133     C.perform(CountEvents(Table, After)); 
    134  
    135     if (After != Before) 
    136       throw logic_error("Event counts changed from " 
    137                         "{" + to_string(Before.first) + "," + 
    138                         to_string(Before.second) + "} " 
    139                         "to " 
    140                         "{" + to_string(After.first) + "," + 
    141                         to_string(After.second) + "} " 
    142                         "despite abort.  This could be a bug in libpqxx, " 
    143                         "or something else modified the table."); 
    144   } 
    145   catch (const sql_error &e) 
    146   { 
    147     // If we're interested in the text of a failed query, we can write separate 
    148     // exception handling code for this type of exception 
    149     cerr << "SQL error: " << e.what() << endl 
    150          << "Query was: '" << e.query() << "'" << endl; 
    151     return 1; 
    152   } 
    153   catch (const exception &e) 
    154   { 
    155     // All exceptions thrown by libpqxx are derived from std::exception 
    156     cerr << "Exception: " << e.what() << endl; 
    157     return 2; 
    158   } 
    159   catch (...) 
    160   { 
    161     // This is really unexpected (see above) 
    162     cerr << "Unhandled exception" << endl; 
    163     return 100; 
    164   } 
    165  
    166   return 0; 
    167 
    168  
     130PQXX_REGISTER_TEST_T(test_013, nontransaction) 
  • trunk/test/test014.cxx

    r1138 r1376  
    1 #include <cassert> 
    21#include <iostream> 
    32 
     
    65#include <pqxx/result> 
    76 
     7#include "test_helpers.hxx" 
     8 
    89using namespace PGSTD; 
    910using namespace pqxx; 
    1011 
    1112 
     13// Simple test program for libpqxx.  Open connection to database, start 
     14// a dummy transaction to gain nontransactional access, and perform a query. 
     15 
     16namespace 
     17{ 
    1218// Define a pqxx::noticer to process warnings generated by the database 
    1319// connection and (in this case) pass them to cerr.  This is optional. 
    14 namespace 
    15 { 
    1620struct ReportWarning : noticer 
    1721{ 
     
    2327  } 
    2428}; 
    25 } 
    2629 
    2730 
    28 // Simple test program for libpqxx.  Open connection to database, start 
    29 // a dummy transaction to gain nontransactional access, and perform a query. 
    30 // 
    31 // Usage: test014 [connect-string] 
    32 // 
    33 // Where connect-string is a set of connection options in Postgresql's 
    34 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    35 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    36 // backend running on host foo.bar.net, logging in as user smith. 
    37 int main(int, char *argv[]) 
     31void test_014(connection_base &C, transaction_base &orgT) 
    3832{ 
    39   try 
     33  orgT.abort(); 
     34 
     35  // Tell C to report its warnings through std::cerr instead of the default 
     36  // (which is to print to stderr).  This is done just to show that the way 
     37  // messages are processed can be changed by the client program. 
     38  noticer *MyNoticer = new ReportWarning; 
     39  // This is not a memory leak: C stores MyNoticer in an auto_ptr that will 
     40  // delete the object on destruction. 
     41  C.set_noticer(auto_ptr<noticer>(MyNoticer)); 
     42 
     43  PQXX_CHECK(C.get_noticer() == MyNoticer, "Lost noticer."); 
     44 
     45  // Now use our noticer to output a diagnostic message.  Note that the 
     46  // message must end in a newline. 
     47  C.process_notice("Opened connection\n"); 
     48 
     49  // ProcessNotice() can take either a C++ string or a C-style const char *. 
     50  const string HostName = (C.hostname() ? C.hostname() : "<local>"); 
     51  C.process_notice(string() + 
     52        "database=" + C.dbname() + ", " 
     53        "username=" + C.username() + ", " 
     54        "hostname=" + HostName + ", " 
     55        "port=" + to_string(C.port()) + ", " 
     56        "options='" + static_cast<connection &>(C).options() + "', " 
     57        "backendpid=" + to_string(C.backendpid()) + "\n"); 
     58 
     59  // Begin a "non-transaction" acting on our current connection.  This is 
     60  // really all the transactional integrity we need since we're only 
     61  // performing one query which does not modify the database. 
     62  nontransaction T(C, "test14"); 
     63 
     64  // The Transaction family of classes also has ProcessNotice() functions. 
     65  // These simply pass the notice through to their connection, but this may 
     66  // be more convenient in some cases.  All ProcessNotice() functions accept 
     67  // C++ strings as well as C strings. 
     68  T.process_notice(string("Started nontransaction\n")); 
     69 
     70  result R( T.exec("SELECT * FROM pg_tables") ); 
     71 
     72  // Give some feedback to the test program's user prior to the real work 
     73  T.process_notice(to_string(R.size()) + " " 
     74        "result tuples in transaction " + 
     75        T.name() + "\n"); 
     76 
     77  for (result::const_iterator c = R.begin(); c != R.end(); ++c) 
    4078  { 
    41     connection C(argv[1]); 
     79    string N; 
     80    c[0].to(N); 
    4281 
    43     // Tell C to report its warnings through std::cerr instead of the default 
    44     // (which is to print to stderr).  This is done just to show that the way 
    45     // messages are processed can be changed by the client program. 
    46     noticer *MyNoticer = new ReportWarning; 
    47     // This is not a memory leak: C stores MyNoticer in an auto_ptr that will 
    48     // delete the object on destruction. 
    49     C.set_noticer(auto_ptr<noticer>(MyNoticer)); 
    50  
    51     assert(C.get_noticer() == MyNoticer); 
    52  
    53     // Now use our noticer to output a diagnostic message.  Note that the 
    54     // message must end in a newline. 
    55     C.process_notice("Opened connection\n"); 
    56  
    57     // ProcessNotice() can take either a C++ string or a C-style const char *. 
    58     const string HostName = (C.hostname() ? C.hostname() : "<local>"); 
    59     C.process_notice(string() + 
    60                      "database=" + C.dbname() + ", " 
    61                      "username=" + C.username() + ", " 
    62                      "hostname=" + HostName + ", " 
    63                      "port=" + to_string(C.port()) + ", " 
    64                      "options='" + C.options() + "', " 
    65                      "backendpid=" + to_string(C.backendpid()) + "\n"); 
    66  
    67     // Begin a "non-transaction" acting on our current connection.  This is 
    68     // really all the transactional integrity we need since we're only 
    69     // performing one query which does not modify the database. 
    70     nontransaction T(C, "test14"); 
    71  
    72     // The Transaction family of classes also has ProcessNotice() functions. 
    73     // These simply pass the notice through to their connection, but this may 
    74     // be more convenient in some cases.  All ProcessNotice() functions accept 
    75     // C++ strings as well as C strings. 
    76     T.process_notice(string("Started nontransaction\n")); 
    77  
    78     result R( T.exec("SELECT * FROM pg_tables") ); 
    79  
    80     // Give some feedback to the test program's user prior to the real work 
    81     T.process_notice(to_string(R.size()) + " " 
    82                     "result tuples in transaction " + 
    83                     T.name() + 
    84                     "\n"); 
    85  
    86     for (result::const_iterator c = R.begin(); c != R.end(); ++c) 
    87     { 
    88       string N; 
    89       c[0].to(N); 
    90  
    91       cout << '\t' << to_string(c.num()) << '\t' << N << endl; 
    92     } 
    93  
    94     // "Commit" the non-transaction.  This doesn't really do anything since 
    95     // NonTransaction doesn't start a backend transaction. 
    96     T.commit(); 
    97   } 
    98   catch (const sql_error &e) 
    99   { 
    100     // If we're interested in the text of a failed query, we can write separate 
    101     // exception handling code for this type of exception 
    102     cerr << "SQL error: " << e.what() << endl 
    103          << "Query was: '" << e.query() << "'" << endl; 
    104     return 1; 
    105   } 
    106   catch (const exception &e) 
    107   { 
    108     // All exceptions thrown by libpqxx are derived from std::exception 
    109     cerr << "Exception: " << e.what() << endl; 
    110     return 2; 
    111   } 
    112   catch (...) 
    113   { 
    114     // This is really unexpected (see above) 
    115     cerr << "Unhandled exception" << endl; 
    116     return 100; 
     82    cout << '\t' << to_string(c.num()) << '\t' << N << endl; 
    11783  } 
    11884 
    119   return 0; 
     85  // "Commit" the non-transaction.  This doesn't really do anything since 
     86  // NonTransaction doesn't start a backend transaction. 
     87  T.commit(); 
    12088} 
     89} // namespace 
    12190 
     91PQXX_REGISTER_TEST_T(test_014, nontransaction) 
  • trunk/test/test015.cxx

    r1040 r1376  
    66#include <pqxx/result> 
    77 
     8#include "test_helpers.hxx" 
     9 
    810using namespace PGSTD; 
    911using namespace pqxx; 
     
    1214// Simple test program for libpqxx.  Open connection to database, start 
    1315// a dummy transaction to gain nontransactional access, and perform a query. 
    14 // 
    15 // Usage: test015 [connect-string] 
    16 // 
    17 // Where connect-string is a set of connection options in Postgresql's 
    18 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    19 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    20 // backend running on host foo.bar.net, logging in as user smith. 
    2116 
     17namespace 
     18{ 
    2219class ReadTables : public transactor<nontransaction> 
    2320{ 
     
    4441 
    4542 
    46 int main(int, char *argv[]
     43void test_015(connection_base &C, transaction_base &ortT
    4744{ 
    48   try 
    49   { 
    50     connection C(argv[1]); 
     45  ortT.abort(); 
    5146 
    52     // See if Deactivate() behaves... 
    53     C.deactivate(); 
     47  // See if Deactivate() behaves... 
     48  C.deactivate(); 
    5449 
    55     C.perform(ReadTables()); 
    56   } 
    57   catch (const sql_error &e) 
    58   { 
    59     // If we're interested in the text of a failed query, we can write separate 
    60     // exception handling code for this type of exception 
    61     cerr << "SQL error: " << e.what() << endl 
    62          << "Query was: '" << e.query() << "'" << endl; 
    63     return 1; 
    64   } 
    65   catch (const exception &e) 
    66   { 
    67     // All exceptions thrown by libpqxx are derived from std::exception 
    68     cerr << "Exception: " << e.what() << endl; 
    69     return 2; 
    70   } 
    71   catch (...) 
    72   { 
    73     // This is really unexpected (see above) 
    74     cerr << "Unhandled exception" << endl; 
    75     return 100; 
    76   } 
    77  
    78   return 0; 
     50  C.perform(ReadTables()); 
    7951} 
    8052 
     53} // namespace 
     54 
     55PQXX_REGISTER_TEST_T(test_015, nontransaction) 
  • trunk/test/test016.cxx

    r1138 r1376  
    44#include <pqxx/robusttransaction> 
    55#include <pqxx/result> 
     6 
     7#include "test_helpers.hxx" 
    68 
    79using namespace PGSTD; 
     
    1113// Simple test program for libpqxx.  Open connection to database, start 
    1214// a dummy transaction to gain nontransactional access, and perform a query. 
    13 // 
    14 // Usage: test016 [connect-string] 
    15 // 
    16 // Where connect-string is a set of connection options in Postgresql's 
    17 // PQconnectdb() format, eg. "dbname=template1" to select from a database 
    18 // called template1, or "host=foo.bar.net user=smith" to connect to a 
    19 // backend running on host foo.bar.net, logging in as user smith. 
    20 int main(int, char *argv[]) 
     15namespace 
    2116{ 
    22   try 
     17 
     18void test_016(connection_base &, transaction_base &T) 
     19
     20  result R( T.exec("SELECT * FROM pg_tables") ); 
     21 
     22  result::const_iterator c; 
     23  for (c = R.begin(); c != R.end(); ++c) 
    2324  { 
    24     connection C(argv[1]); 
     25    string N; 
     26    c[0].to(N); 
    2527 
    26     // Begin a "non-transaction" acting on our current connection.  This is 
    27     // really all the transactional integrity we need since we're only 
    28     // performing one query which does not modify the database. 
    29     robusttransaction<> T(C, "test16"); 
    30  
    31     result R( T.exec("SELECT * FROM pg_tables") ); 
    32  
    33     result::const_iterator c; 
    34     for (c = R.begin(); c != R.end(); ++c) 
    35     { 
    36       string N; 
    37       c[0].to(N); 
    38  
    39       cout << '\t' << to_string(c.num()) << '\t' << N << endl; 
    40     } 
    41  
    42     // See if back() and tuple comparison work properly 
    43     if (R.size() < 2) 
    44       throw runtime_error("Not enough results in pg_tables to test, sorry!"); 
    45     --c; 
    46     if (c->size() != R.back().size()) 
    47       throw logic_error("Size mismatch between tuple iterator and back()"); 
    48     const string nullstr; 
    49     for (result::tuple::size_type i = 0; i < c->size(); ++i) 
    50       if (c[i].as(nullstr) != R.back()[i].as(nullstr)) 
    51         throw logic_error("Value mismatch in back()"); 
    52     if (c != R.back()) 
    53       throw logic_error("Something wrong with tuple inequality"); 
    54     if (!(c == R.back())) 
    55       throw logic_error("Something wrong with tuple equality"); 
    56  
    57     // "Commit" the non-transaction.  This doesn't really do anything since 
    58     // NonTransaction doesn't start a backend transaction. 
    59     T.commit(); 
    60   } 
    61   catch (const sql_error &e) 
    62   { 
    63     // If we're interested in the text of a failed query, we can write separate 
    64     // exception handling code for this type of exception 
    65     cerr << "SQL error: " << e.what() << endl 
    66          << "Query was: '" << e.query() << "'" << endl; 
    67     return 1; 
    68   } 
    69   catch (const exception &e) 
    70   { 
    71     // All exceptions thrown by libpqxx are derived from std::exception 
    72     cerr << "Exception: " << e.what() << endl; 
    73     return 2; 
    74   } 
    75   catch (...) 
    76   { 
    77     // This is really unexpected (see above) 
    78     cerr << "Unhandled exception" << endl; 
    79     return 100; 
     28    cout << '\t' << to_string(c.num()) << '\t' << N << endl; 
    8029  } 
    8130 
    82   return 0; 
     31  // See if back() and tuple comparison work properly 
     32  if (R.size() < 2) 
     33    throw runtime_error("Not enough results in pg_tables to test, sorry!"); 
     34  --c; 
     35  if (c->size() != R.back().size()) 
     36    throw logic_error("Size mismatch between tuple iterator and back()"); 
     37  const string nullstr; 
     38  for (result::tuple::size_type i = 0; i < c->size(); ++i) 
     39    if (c[i].as(nullstr) != R.back()[i].as(nullstr)) 
     40        throw logic_error("Value mismatch in back()"); 
     41  if (c != R.back()) 
     42    throw logic_error("Something wrong with tuple inequality"); 
     43  if (!(c == R.back())) 
     44    throw logic_error("Something wrong with tuple equality"); 
     45 
     46  // "Commit" the non-transaction.  This doesn't really do anything since 
     47  // NonTransaction doesn't start a backend transaction. 
     48  T.commit(); 
    8349} 
     50} // namespace 
    8451 
     52PQXX_REGISTER_TEST_T(test_016, robusttransaction<>) 
  • trunk/test/test_helpers.hxx

    r1375 r1376  
    295295 
    296296 
     297// Support string conversion on result rows for debug output. 
     298template<> struct string_traits<result::tuple> 
     299{ 
     300  static const char *name() { return "pqxx::result::tuple"; } 
     301  static bool has_null() { return false; } 
     302  static bool is_null(result::tuple) { return false; } 
     303  static result null(); // Not needed 
     304  static void from_string(const char Str[], result &Obj); // Not needed 
     305  static PGSTD::string to_string(result::tuple Obj) 
     306  { 
     307    return separated_list(", ", Obj.begin(), Obj.end(), deref_field); 
     308  } 
     309}; 
     310 
    297311// Support string conversion on result objects for debug output. 
    298312template<> struct string_traits<result> 
     
    306320  { 
    307321    if (is_null(Obj)) return "<empty>"; 
    308  
    309     PGSTD::string out; 
    310     for (result::const_iterator row = Obj.begin(); row != Obj.end(); ++row) 
    311     { 
    312       out += "{" + 
    313         separated_list(", ", row.begin(), row.end(), deref_field) + 
    314         "}"; 
    315     } 
    316     return out; 
    317   } 
    318 }; 
     322    return "{" + separated_list("}\n{", Obj) + "}"; 
     323  } 
     324}; 
     325 
     326// Support string conversion on result::const_iterator for debug output. 
     327template<> struct string_traits<result::const_iterator> 
     328
     329  typedef result::const_iterator subject_type; 
     330  static const char *name() { return "pqxx::result::const_iterator"; } 
     331  static bool has_null() { return false; } 
     332  static bool is_null(subject_type) { return false; } 
     333  static result null(); // Not needed 
     334  static void from_string(const char Str[], subject_type &Obj); // Not needed 
     335  static PGSTD::string to_string(subject_type Obj) 
     336  { 
     337    return "<iterator at " + pqxx::to_string(Obj.rownumber()) + ">"; 
     338  } 
     339}; 
     340 
    319341 
    320342// Support string conversion on vector<string> for debug output.