
This patch adds missing files to 1.2.1 tarball.

diff -urN liblas-1.2.1/test/unit/common.hpp main/test/unit/common.hpp
--- liblas-1.2.1/test/unit/common.hpp	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/common.hpp	2009-10-02 16:46:22.000000000 +0200
@@ -0,0 +1,88 @@
+// $Id$
+//
+// (C) Copyright Mateusz Loskot 2008, mateusz@loskot.net
+// Distributed under the BSD License
+// (See accompanying file LICENSE.txt or copy at
+// http://www.opensource.org/licenses/bsd-license.php)
+//
+#include <liblas/liblas.hpp>
+#include <liblas/laspoint.hpp>
+#include <liblas/lasheader.hpp>
+
+
+namespace tut
+{
+
+// Predicate testing LASPoint against given XY coordinates
+// and tolerance.
+struct is_xy
+{
+    is_xy(double x, double y, double tolerance)
+        : x(x), y(y), t(tolerance)
+    {}
+
+    bool operator()(liblas::LASPoint const& p)
+    {
+        double const dx = x - p.GetX();
+        double const dy = y - p.GetY();
+
+        return ((dx <= t && dx >= -t) && (dy <= t && dy >= -t));
+    }
+
+    double x;
+    double y;
+    double t;
+};
+
+// Functor to calculate bounding box of a set of points
+struct bbox_calculator
+{
+    // bbox object will store operation result
+    bbox_calculator(liblas::detail::Extents<double>& bbox)
+        : empty(true), bbox(bbox)
+    {}
+
+    void operator()(liblas::LASPoint const& p)
+    {
+        // Box initialization during first iteration only
+        if (empty)
+        {
+            bbox.min.x = bbox.max.x = p.GetX();
+            bbox.min.y = bbox.max.y = p.GetY();
+            bbox.min.z = bbox.max.z = p.GetZ();
+            empty = false;
+        }
+
+        // Expand bounding box to include given point
+        bbox.min.x = std::min(bbox.min.x, p.GetX());
+        bbox.min.y = std::min(bbox.min.y, p.GetY());
+        bbox.min.z = std::min(bbox.min.z, p.GetZ());
+        bbox.max.x = std::max(bbox.max.x, p.GetX());
+        bbox.max.y = std::max(bbox.max.y, p.GetY());
+        bbox.max.z = std::max(bbox.max.z, p.GetZ());
+    }
+
+    bool empty;
+    liblas::detail::Extents<double>& bbox;
+};
+
+// Common test procedure for default constructed point data.
+void test_default_point(liblas::LASPoint const& p);
+
+// Common test procedure for default constructed header data.
+void test_default_header(liblas::LASHeader const& h);
+
+// Test of header data in trunk/test/data/TO_core_last_clip.las file
+void test_file10_header(liblas::LASHeader const& h);
+
+// Test of 1st point record in trunk/test/data/TO_core_last_clip.las file
+void test_file10_point1(liblas::LASPoint const& p);
+
+// Test of 2nd point record in trunk/test/data/TO_core_last_clip.las file
+void test_file10_point2(liblas::LASPoint const& p);
+
+// Test of 4th point record in trunk/test/data/TO_core_last_clip.las file
+void test_file10_point4(liblas::LASPoint const& p);
+
+} // namespace tut
+
diff -urN liblas-1.2.1/test/unit/liblas_test.hpp main/test/unit/liblas_test.hpp
--- liblas-1.2.1/test/unit/liblas_test.hpp	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/liblas_test.hpp	2009-10-02 16:46:22.000000000 +0200
@@ -0,0 +1,18 @@
+// $Id$
+//
+// (C) Copyright Mateusz Loskot 2008, mateusz@loskot.net
+// Distributed under the BSD License
+// (See accompanying file LICENSE.txt or copy at
+// http://www.opensource.org/licenses/bsd-license.php)
+//
+#ifndef LIBLAS_TEST_HPP_INCLUDED
+#define LIBLAS_TEST_HPP_INCLUDED
+
+namespace tut
+{
+    // full path to trunk/test/data
+    extern std::string g_test_data_path;
+}
+
+#endif // LIBLAS_TEST_HPP_INCLUDED
+
diff -urN liblas-1.2.1/test/unit/tut/README main/test/unit/tut/README
--- liblas-1.2.1/test/unit/tut/README	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/tut/README	2009-10-02 16:46:36.000000000 +0200
@@ -0,0 +1,516 @@
+--------------------------------------------------------------------
+TUT: C++ Template Unit Test Framework
+
+Version:  TUT-2007-07-06
+Homepage: http://tut-framework.sourceforge.net/
+--------------------------------------------------------------------
+
+Documentation TUT How-To minimum steps to make TUT work for you
+
+What is TUT
+
+TUT is a pure C++ unit test framework. Its name - TUT - stands for 
+Template Unit Tests.
+
+Features
+
+TUT provides all features required for unit testing:
+
+    * Similar tests can be grouped together into test groups. Each 
+      test group has its unique name and is located in a separate 
+      compilation unit. One group can contain almost unlimited number 
+      of tests (actually, the limit is the compiler template 
+      recursion depth).
+    * User can run all the tests (regression), or just some selected 
+      groups or even some tests in these groups.
+    * TUT provides special template functions to check the condition 
+      validity at run-time and to force test failure if required. 
+      Since C++ doesn't provide a facility for obtaining stack trace 
+      of the throwed exception and TUT avoids macros, those functions 
+      accept string marker to allow users easely determine the source 
+      of exception.
+    * TUT contains callback that can be implemented by the calling code 
+      to integrate with an IDE, for example. Callbacks tell listener 
+      when a new test run started, when test runner switches to the 
+      next tests group, when a test was completed (and what result it 
+      has), and when test run was finished. The callbacks allow users 
+      to produce their own visualization format for test process and results.
+    * Being a template library, it doesn't need compilation; just 
+      include the <tut.h> header into the test modules.
+
+TUT tests organization
+
+Test application
+
+C++ produces executable code, so tests have to be compiled into a single 
+binary called test application. The application can be built in automated 
+mode to perform nightly tests. They also can be built manually when a 
+developer hunts for bugs.
+
+The test application contains tests, organized into test groups.
+
+Test groups
+
+The functionality of a tested application can be divided into a few separate 
+function blocks (e.g. User Rights, Export, Processing, ...). It is natural 
+to group together tests for each block. TUT invokes this test group. Each 
+test group has a unique human-readable name and normally is located in a 
+separate file.
+
+Tests
+
+Each single test usually checks only one specific element of functionality. 
+For example, for a container a test could check whether size() call 
+returns zero after the successful call to the clear() method.
+
+Writing simple test
+
+Preamble
+
+You are going to create a new class for your application. You decided to 
+write tests for the class to be sure it works while you are developing or, 
+possibly, enhancing it. Let's consider your class is shared pointer: 
+std::auto_ptr-alike type that shares the same object among instances.
+
+Prior to test writing, you should decide what to test. Maximalist's 
+approach requires to write so many tests that altering any single 
+line of your production code will break at least one of them. 
+Minimalist's approach allows one to write tests only for the most 
+general or the most complex use cases. The truth lies somewhere in 
+between, but only you, developer, know where. You should prepare 
+common successful and unsuccessful scenarios, and the scenarios for 
+testing any other functionality you believe might be broken in some way.
+
+For our shared_ptr we obviosly should test constructors, assignment operators, referencing and passing ownership.
+
+Skeleton
+
+If you don't have any implemented class to test yet, it would be good to 
+implement it as a set of stubs for a first time. Thus you'll get an 
+interface, and be able to write your tests. Yes, that's correct: you 
+should write your tests before writing code! First of all, writing tests 
+often helps to understand oddities in the current interface, and fix it. 
+Secondly, with the stubs all your tests will fail, so you'll be sure 
+they do their job.
+
+Creating Test Group
+
+Since we're writing unit tests, it would be a good idea to group the 
+tests for our class in one place to be able to run them separately. 
+It's also natural in C++ to place all the grouped tests into one 
+compilation unit (i.e. source file). So, to begin, we should create 
+a new file. Let's call it test_shared_ptr.cpp. (Final variant of the 
+test group can be found in examples/shared_ptr subdirectory of the 
+distribution package)
+
+// test_shared_ptr.cpp
+#include <tut.h>
+
+namespace tut
+{
+};
+            
+
+As you see, you need to include TUT header file (as expected) and 
+use namespace tut for tests. You may also use anonymous namespace if 
+your compiler allows it (you will need to instantiate methods from 
+tut namespace and some compilers refuse to place such instantiations 
+into the anonymous namespace).
+
+A test group in TUT framework is described by the special template 
+test_group<T>. The template parameter T is a type that will hold all 
+test-specific data during the test execution. Actually, the data 
+stored in T are member data of the test. Test object is inherited 
+from T, so any test can refer to the data in T as its member data.
+
+For simple test groups (where all data are stored in test local 
+variables) type T is an empty struct.
+
+#include <tut.h>
+
+namespace tut
+{
+  struct shared_ptr_data
+  { 
+  };
+}
+            
+But when tests have complex or repeating creation phase, you may put 
+data members into the T and provide constructor (and, if required, 
+destructor) for it. For each test, a new instance of T will be 
+created. To prepare your test for execution TUT will use default 
+constructor. Similarly, after the test has been finished, TUT 
+calls the destructor to clean up T. I.e.:
+
+#include <tut.h>
+
+namespace tut
+{
+  struct complex_data
+  {
+    connection* con;
+    complex_data(){ con = db_pool.get_connection(); }
+    ~complex_data(){ db_pool.release_connection(con); }
+  };
+
+  // each test from now will have con data member initialized
+  // by constructor:
+  ...
+  con->commit();
+  ...
+            
+
+What will happen if the constructor throws an exception? TUT will treat 
+it as if test itself failed with exception, so this test will 
+not be executed. You'll see an exception mark near the test, and 
+if the constructor throwed something printable, a certain message will appear.
+
+Exception in destructor is threated a bit different. Reaching destruction 
+phase means that the test is passed, so TUT marks test with warning 
+status meaning that test itself was OK, but something bad has happend 
+after the test.
+
+Well, all we have written so far is just a type declaration. To work 
+with a group we have to have an object, so we must create the test group 
+object. Since we need only one test group object for each unit, we can 
+(and should, actually) make this object static. To prevent name clash with 
+other test group objects in the namespace tut, we should provide a 
+descriptive name, or, alternatively, we may put it into the anonymous 
+namespace. The former is more correct, but a descriptive name usually works 
+well too, unless you're too terse in giving names to objects.
+
+#include <tut.h>
+
+namespace tut
+{
+    struct shared_ptr_data
+    {
+
+    };
+
+    typedef test_group<shared_ptr_data> tg;
+    tg shared_ptr_group("shared_ptr");
+};
+            
+As you see, any test group accepts a single parameter - its human-readable 
+name. This name is used to identify the group when a programmer wants to 
+execute all tests or a single test within the group. So this name shall 
+also be descriptive enough to avoid clashes. Since we're writing tests 
+for a specific unit, it's enough to name it after the unit name.
+
+Test group constructor will be called at unspecified moment at the test 
+application startup. The constructor performs self-registration; it calls 
+tut::runner and asks it to store the test group object name and location. 
+Any other test group in the system undergoes the same processing, i.e. 
+each test group object registers itself. Thus, test runner can iterate 
+all test groups or execute any test group by its name.
+
+Newly created group has no tests associated with it. To be more precise, 
+it has predefined set of dummy tests. By default, there are 50 tests in a 
+group, including dummy ones. To create a test group with higher volume 
+(e.g. when tests are generated by a script and their number is higher) 
+we must provide a higher border of test group size when it is instantiated:
+
+#include <tut.h>
+
+namespace tut
+{
+    struct huge_test_data
+    {
+    };
+
+    // test group with maximum 500 tests
+    typedef test_group<huge_test_data,500> testgroup;
+    testgroup huge_test_testgroup("huge group");
+};
+            
+
+Note also, that your compiler will possibly need a command-line switch 
+or pragma to enlarge recursive instantiation depth. For g++, for 
+example, you should specify at least --ftemplate-depth-501 to increase 
+the depth. For more information see your compiler documentation.
+
+Creating Tests
+
+Now it's time to fill our test group with content.
+
+In TUT, all tests have unique numbers inside the test group. Some 
+people believe that textual names better describe failed tests in 
+reports. I agree; but in reality C++ templates work good with numbers 
+because they are compile-time constants and refuse to do the same 
+with strings, since strings are in fact addresses of character 
+buffers, i.e. run-time data.
+
+As I mentioned above, our test group already has a few dummy tests; 
+and we can replace any of them with something real just by writing 
+our own version:
+
+#include <tut.h>
+
+namespace tut
+{
+    struct shared_ptr_data{};
+
+    typedef test_group<shared_ptr_data> testgroup;
+    typedef testgroup::object testobject;
+    testgroup shared_ptr_testgroup("shared_ptr");
+
+    template<>
+    template<>
+    void testobject::test<1>()
+    {
+        // do nothing test
+    }
+};
+        
+
+So far this test does nothing, but it's enough to illustrate the concept.
+
+All tests in the group belong to the type test_group<T>::object. This 
+class is directly inherited from our test data structure. In our case, it is
+
+class object : public shared_ptr_data { ... }
+        
+This allows to access members of the data structure directly, since at 
+the same time they are members of the object type. We also typedef the 
+type with testobject for brevity.
+
+We mark our test with number 1. Previously, test group had a dummy test 
+with the same number, but now, since we've defined our own version, it 
+replaces the dummy test as more specialized one. It's how C++ template 
+ordering works.
+
+The test we've written always succeeds. Successful test returns with no 
+exceptions. Unsuccessful one either throws an exception, or fails at 
+fail() or ensure() methods (which anyway just throw the exception when failed).
+
+First real test
+
+Well, now we know enough to write the first real working test. This test 
+will create shared_ptr instances and check their state. We will define a 
+small structure (keepee) to use it as shared_ptr stored object type.
+
+#include <tut.h>
+#include <shared_ptr.h>
+
+namespace tut
+{
+    struct shared_ptr_data
+    {
+        struct keepee{ int data; };
+    };
+
+    typedef test_group<shared_ptr_data> testgroup;
+    typedef testgroup::object testobject;
+    testgroup shared_ptr_testgroup("shared_ptr");
+
+    /**
+     * Checks default constructor.
+     */
+    template<>
+    template<>
+    void testobject::test<1>()
+    {
+        shared_ptr<keepee> def;
+        ensure("null",def.get() == 0);
+    }
+};
+        
+
+That's all! The first line creates shared_ptr. If constructor throws 
+an exception, test will fail (exceptions, including '...', are catched 
+by the TUT framework). If the first line succeeds, we must check 
+whether the kept object is null one. To do this, we use test object 
+member function ensure(), which throws std::logic_error with a given 
+message if its second argument is not true. Finally, if destructor of 
+shared_ptr fails with exception, TUT also will report this test as failed.
+
+It's equally easy to write a test for the scenario where we expect to get 
+an exception: let's consider our class should throw an exception if it 
+has no stored object, and the operator -> is called.
+
+/**
+ * Checks operator -> throws instead of returning null.
+ */
+template<>
+template<>
+void testobject::test<2>()
+{
+    try
+    {
+        shared_ptr<keepee> sp;
+        sp->data = 0;
+        fail("exception expected");
+    }
+    catch( const std::runtime_error& ex )
+    {
+        // ok
+    }
+}
+        
+
+Here we expect the std::runtime_error. If operator doesn't throw it, 
+we'll force the test to fail using another member function: fail(). It 
+just throws std::logic_error with a given message. If operator throws 
+anything else, our test will fail too, since we intercept only 
+std::runtime_error, and any other exception means the test has failed.
+
+NB: our second test has number 2 in its name; it can, actually, be any 
+in range 1..Max; the only requirement is not to write tests with the 
+same numbers. If you did, compiler will force you to fix them anyway.
+
+And finally, one more test to demonstrate how to use the 
+ensure_equals template member function:
+
+/**
+ * Checks keepee counting.
+ */
+template<>
+template<>
+void testobject::test<3>()
+{
+    shared_ptr<keepee> sp1(new keepee());
+    shared_ptr<keepee> sp2(sp1);
+    ensure_equals("second copy at sp1",sp1.count(),2);
+    ensure_equals("second copy at sp2",sp2.count(),2);
+}
+        
+
+The test checks if the shared_ptr correctly counts references during 
+copy construction. What's interesting here is the template member 
+ensure_equals. It has an additional functionality comparing with similar 
+call ensure("second_copy",sp1.count()==2); it uses operator == to check 
+the equality of the two passed parameters and, what's more important, it 
+uses std::stream to format the passed parameters into a human-readable 
+message (smth like: "second copy: expected 2, got 1"). It means that 
+ensure_equals cannot be used with the types that don't have operator <<; 
+but for those having the operator it provides much more informational message.
+
+In contrast to JUnit assertEquals, where the expected value goes before 
+the actual one, ensure_equals() accepts the expected after the actual 
+value. I believe it's more natural to read ensure_equals("msg", count, 5) 
+as "ensure that count equals to 5" rather than JUnit's 
+"assert that 5 is the value of the count".
+
+Running tests
+
+Tests are already written, but an attempt to run them will be unsuccessful. 
+We need a few other bits to complete the test application.
+
+First of all, we need a main() method, simply because it must be in all 
+applications. Secondly, we need a test runner singleton. Remember I said 
+each test group should register itself in singleton? So, we need that 
+singleton. And, finally, we need a kind of a callback handler to visualize 
+our test results.
+
+The design of TUT doesn't strictly set a way the tests are visualized; 
+instead, it provides an opportunity to get the test results by means of 
+callbacks. Moreover it allows user to output the results in any format he 
+prefers. Of course, there is a "reference implementation" in the 
+example/subdirectory of the project.
+
+Test runner singleton is defined in tut.h, so all we need to activate it 
+is to declare an object of the type tut::test_runner_singleton in the main 
+module with a special name tut::runner.
+
+Now, with the test_runner we can run tests. Singleton has method get() 
+returning a reference to an instance of the test_runner class, which in 
+turn has methods run_tests() to run all tests in all groups, 
+run_tests(const std::string& groupname) to run all tests in a given group 
+and run_test(const std::string& grp,int n) to run one test in the specified group.
+
+// main.cpp
+#include <tut.h>
+
+namespace tut
+{
+    test_runner_singleton runner;
+}
+
+int main()
+{
+    // run all tests in all groups
+    runner.get().run_tests();
+
+    // run all tests in group "shared_ptr"
+    runner.get().run_tests("shared_ptr");
+
+    // run test number 5 in group "shared_ptr"
+    runner.get().run_test("shared_ptr",5);
+
+    return 0;
+}
+  
+It's up to user to handle command-line arguments or GUI messages and map those 
+arguments/messages to actual calls to test runner. Again, as you see, TUT 
+doesn't restrict user here.
+
+But, the last question is still unanswered: how do we get our test results? 
+The answer lies inside tut::callback interface. User shall create its subclass, 
+and write up to three simple methods. He also can omit any method since they 
+have default no-op implementation. Each corresponding method is called in the 
+following cases:
+
+    * a new test run started;
+    * test finished;
+    * test run finished.
+
+Here is a minimal implementation:
+
+class visualizator : public tut::callback
+{
+public:
+  void run_started(){ }
+
+  void test_completed(const tut::test_result& tr)
+  {
+      // ... show test result here ...
+  }
+
+  void run_completed(){ }
+};        
+
+The most important is the test_completed() method; its parameter has type 
+test_result, and contains everything about the finished test, from its group 
+name and number to the exception message, if any. Member result is an enum 
+that contains status of the test: ok, fail or ex. Take a look at the 
+examples/basic/main.cpp for more complete visualizator.
+
+Visualizator should be passed to the test_runner before run. Knowing that, 
+we are ready to write the final version of our main module:
+
+// main.cpp
+#include <tut.h>
+
+namespace tut
+{
+  test_runner_singleton runner;
+}
+
+class callback : public tut::callback
+{
+public:
+  void run_started(){ std::cout << "\nbegin"; }
+
+  void test_completed(const tut::test_result& tr)
+  {
+    std::cout << tr.test_pos << "=" << tr.result << std::flush;
+  }
+
+  void run_completed(){ std::cout << "\nend"; }
+};
+
+int main()
+{
+  callback clbk;
+  runner.get().set_callback(&clbk);
+
+  // run all tests in all groups
+  runner.get().run_tests();
+  return 0;
+}
+        
+That's it. You are now ready to link and run our test application. Do it as often as possible; 
+once a day is a definite must. I hope, TUT will help you to make your application more 
+robust and relieve your testing pain. Feel free to send your questions, suggestions and 
+critical opinions to me; I'll do my best to address them asap.
diff -urN liblas-1.2.1/test/unit/tut/tut.hpp main/test/unit/tut/tut.hpp
--- liblas-1.2.1/test/unit/tut/tut.hpp	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/tut/tut.hpp	2009-10-02 16:46:36.000000000 +0200
@@ -0,0 +1,1211 @@
+#ifndef TUT_H_GUARD
+#define TUT_H_GUARD
+
+#include <iostream>
+#include <map>
+#include <vector>
+#include <string>
+#include <sstream>
+#include <typeinfo>
+// NOTE: mloskot added for ensure_equals<double,double> specialization
+#include <iomanip>
+#include <limits>
+
+#if defined(TUT_USE_SEH)
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+/**
+ * Template Unit Tests Framework for C++.
+ * http://tut.dozen.ru
+ *
+ * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com
+ */
+namespace tut
+{
+
+/**
+ * The base for all TUT exceptions.
+ */
+struct tut_error : public std::exception
+{
+    tut_error(const std::string& msg)
+        : err_msg(msg)
+    {
+    }
+    
+    ~tut_error() throw()
+    {
+    }
+    
+    const char* what() const throw()
+    {
+        return err_msg.c_str();
+    }
+    
+private:
+
+    std::string err_msg;
+};
+
+/**
+ * Exception to be throwed when attempted to execute 
+ * missed test by number.
+ */
+struct no_such_test : public tut_error
+{
+    no_such_test() 
+        : tut_error("no such test")
+    {
+    }
+    
+    ~no_such_test() throw()
+    {
+    }
+};
+
+/**
+ * No such test and passed test number is higher than
+ * any test number in current group. Used in one-by-one
+ * test running when upper bound is not known.
+ */
+struct beyond_last_test : public no_such_test
+{
+    beyond_last_test()
+    {
+    }
+    
+    ~beyond_last_test() throw()
+    {
+    }
+};
+
+/**
+ * Group not found exception.
+ */
+struct no_such_group : public tut_error
+{
+    no_such_group(const std::string& grp) 
+        : tut_error(grp)
+    {
+    }
+    
+    ~no_such_group() throw()
+    {
+    }
+};
+
+/**
+ * Internal exception to be throwed when 
+ * no more tests left in group or journal.
+ */
+struct no_more_tests
+{
+    no_more_tests()
+    {
+    }
+    
+    ~no_more_tests() throw()
+    {
+    }
+};
+
+/**
+ * Internal exception to be throwed when 
+ * test constructor has failed.
+ */
+struct bad_ctor : public tut_error
+{
+    bad_ctor(const std::string& msg) 
+        : tut_error(msg)
+    {
+    }
+    
+    ~bad_ctor() throw()
+    {
+    }
+};
+
+/**
+ * Exception to be throwed when ensure() fails or fail() called.
+ */
+struct failure : public tut_error
+{
+    failure(const std::string& msg) 
+        : tut_error(msg)
+    {
+    }
+    
+    ~failure() throw()
+    {
+    }
+};
+
+/**
+ * Exception to be throwed when test desctructor throwed an exception.
+ */
+struct warning : public tut_error
+{
+    warning(const std::string& msg) 
+        : tut_error(msg)
+    {
+    }
+    
+    ~warning() throw()
+    {
+    }
+};
+
+/**
+ * Exception to be throwed when test issued SEH (Win32)
+ */
+struct seh : public tut_error
+{
+    seh(const std::string& msg) 
+        : tut_error(msg)
+    {
+    }
+    
+    ~seh() throw()
+    {
+    }
+};
+
+/**
+ * Return type of runned test/test group.
+ *
+ * For test: contains result of test and, possible, message
+ * for failure or exception.
+ */
+struct test_result
+{
+    /**
+     * Test group name.
+     */
+    std::string group;
+
+    /**
+     * Test number in group.
+     */
+    int test;
+
+    /**
+     * Test name (optional)
+     */
+    std::string name;
+
+    /**
+     * ok - test finished successfully
+     * fail - test failed with ensure() or fail() methods
+     * ex - test throwed an exceptions
+     * warn - test finished successfully, but test destructor throwed
+     * term - test forced test application to terminate abnormally
+     */
+    enum result_type
+    { 
+        ok, 
+        fail, 
+        ex, 
+        warn, 
+        term, 
+        ex_ctor 
+    };
+    
+    result_type result;
+
+    /**
+     * Exception message for failed test.
+     */
+    std::string message;
+    std::string exception_typeid;
+
+    /**
+     * Default constructor.
+     */
+    test_result()
+        : test(0),
+          result(ok)
+    {
+    }
+
+    /**
+     * Constructor.
+     */
+    test_result(const std::string& grp, int pos,
+                const std::string& test_name, result_type res)
+        : group(grp), 
+          test(pos), 
+          name(test_name), 
+          result(res)
+    {
+    }
+
+    /**
+     * Constructor with exception.
+     */
+    test_result(const std::string& grp,int pos,
+                const std::string& test_name, result_type res,
+                const std::exception& ex)
+        : group(grp), 
+          test(pos), 
+          name(test_name), 
+          result(res),
+          message(ex.what()),
+          exception_typeid(typeid(ex).name())
+    {
+    }
+};
+
+/**
+ * Interface.
+ * Test group operations.
+ */
+struct group_base
+{
+    virtual ~group_base()
+    {
+    }
+
+    // execute tests iteratively
+    virtual void rewind() = 0;
+    virtual test_result run_next() = 0;
+
+    // execute one test
+    virtual test_result run_test(int n) = 0;
+};
+
+/**
+ * Test runner callback interface.
+ * Can be implemented by caller to update
+ * tests results in real-time. User can implement 
+ * any of callback methods, and leave unused 
+ * in default implementation.
+ */
+struct callback
+{
+    /**
+     * Virtual destructor is a must for subclassed types.
+     */
+    virtual ~callback()
+    {
+    }
+
+    /**
+     * Called when new test run started.
+     */
+    virtual void run_started()
+    {
+    }
+
+    /**
+     * Called when a group started
+     * @param name Name of the group
+     */
+    virtual void group_started(const std::string& /*name*/)
+    {
+    }
+
+    /**
+     * Called when a test finished.
+     * @param tr Test results.
+     */
+    virtual void test_completed(const test_result& /*tr*/)
+    {
+    }
+
+    /**
+     * Called when a group is completed
+     * @param name Name of the group
+     */
+    virtual void group_completed(const std::string& /*name*/)
+    {
+    }
+
+    /**
+     * Called when all tests in run completed.
+     */
+    virtual void run_completed()
+    {
+    }
+};
+
+/**
+ * Typedef for runner::list_groups()
+ */
+typedef std::vector<std::string> groupnames;
+
+/**
+ * Test runner.
+ */
+class test_runner
+{
+
+public:
+    
+    /**
+     * Constructor
+     */
+    test_runner() 
+        : callback_(&default_callback_)
+    {
+    }
+
+    /**
+     * Stores another group for getting by name.
+     */
+    void register_group(const std::string& name, group_base* gr)
+    {
+        if (gr == 0)
+        {
+            throw tut_error("group shall be non-null");
+        }
+
+        // TODO: inline variable
+        groups::iterator found = groups_.find(name);
+        if (found != groups_.end())
+        {
+            std::string msg("attempt to add already existent group " + name);
+            // this exception terminates application so we use cerr also
+            // TODO: should this message appear in stream?
+            std::cerr << msg << std::endl;
+            throw tut_error(msg);
+        }
+
+        groups_[name] = gr;
+    }
+
+    /**
+     * Stores callback object.
+     */
+    void set_callback(callback* cb)
+    {
+        callback_ = cb == 0 ? &default_callback_ : cb;
+    }
+
+    /**
+     * Returns callback object.
+     */
+    callback& get_callback() const
+    {
+        return *callback_;
+    }
+
+    /**
+     * Returns list of known test groups.
+     */
+    const groupnames list_groups() const
+    {
+        groupnames ret;
+        const_iterator i = groups_.begin();
+        const_iterator e = groups_.end();
+        while (i != e)
+        {
+            ret.push_back(i->first);
+            ++i;
+        }
+        return ret;
+    }
+
+    /**
+     * Runs all tests in all groups.
+     * @param callback Callback object if exists; null otherwise
+     */
+    void run_tests() const
+    {
+        callback_->run_started();
+
+        const_iterator i = groups_.begin();
+        const_iterator e = groups_.end();
+        while (i != e)
+        {
+            callback_->group_started(i->first);
+            try
+            {
+                run_all_tests_in_group_(i);
+            }
+            catch (const no_more_tests&)
+            {
+                callback_->group_completed(i->first);
+            }
+
+            ++i;
+        }
+
+        callback_->run_completed();
+    }
+
+    /**
+     * Runs all tests in specified group.
+     */
+    void run_tests(const std::string& group_name) const
+    {
+        callback_->run_started();
+
+        const_iterator i = groups_.find(group_name);
+        if (i == groups_.end())
+        {
+            callback_->run_completed();
+            throw no_such_group(group_name);
+        }
+
+        callback_->group_started(group_name);
+        try
+        {
+            run_all_tests_in_group_(i);
+        }
+        catch (const no_more_tests&)
+        {
+            // ok
+        }
+
+        callback_->group_completed(group_name);
+        callback_->run_completed();
+    }
+
+    /**
+     * Runs one test in specified group.
+     */
+    test_result run_test(const std::string& group_name, int n) const
+    {
+        callback_->run_started();
+
+        const_iterator i = groups_.find(group_name);
+        if (i == groups_.end())
+        {
+            callback_->run_completed();
+            throw no_such_group(group_name);
+        }
+
+        callback_->group_started(group_name);
+        try
+        {
+            test_result tr = i->second->run_test(n);
+            callback_->test_completed(tr);
+            callback_->group_completed(group_name);
+            callback_->run_completed();
+            return tr;
+        }
+        catch (const beyond_last_test&)
+        {
+            callback_->group_completed(group_name);
+            callback_->run_completed();
+            throw;
+        }
+        catch (const no_such_test&)
+        {
+            callback_->group_completed(group_name);
+            callback_->run_completed();
+            throw;
+        }
+    }
+
+protected:
+    
+    typedef std::map<std::string, group_base*> groups;
+    typedef groups::iterator iterator;
+    typedef groups::const_iterator const_iterator;
+    groups groups_;
+
+    callback  default_callback_;
+    callback* callback_;
+
+
+private:
+
+    void run_all_tests_in_group_(const_iterator i) const
+    {
+        i->second->rewind();
+        for ( ;; )
+        {
+            test_result tr = i->second->run_next();
+            callback_->test_completed(tr);
+
+            if (tr.result == test_result::ex_ctor)
+            {
+                throw no_more_tests();
+            }
+        }
+    }
+};
+
+/**
+ * Singleton for test_runner implementation.
+ * Instance with name runner_singleton shall be implemented
+ * by user.
+ */
+class test_runner_singleton
+{
+public:
+
+    static test_runner& get()
+    {
+        static test_runner tr;
+        return tr;
+    }
+};
+
+extern test_runner_singleton runner;
+
+/**
+ * Test object. Contains data test run upon and default test method 
+ * implementation. Inherited from Data to allow tests to  
+ * access test data as members.
+ */
+template <class Data>
+class test_object : public Data
+{
+public:
+
+    /**
+     * Default constructor
+     */
+    test_object()
+    {
+    }
+
+    void set_test_name(const std::string& current_test_name)
+    {
+        current_test_name_ = current_test_name;
+    }
+
+    const std::string& get_test_name() const
+    {
+        return current_test_name_;
+    }
+
+    /**
+     * Default do-nothing test.
+     */
+    template <int n>
+    void test()
+    {
+        called_method_was_a_dummy_test_ = true;
+    }
+
+    /**
+     * The flag is set to true by default (dummy) test.
+     * Used to detect usused test numbers and avoid unnecessary
+     * test object creation which may be time-consuming depending
+     * on operations described in Data::Data() and Data::~Data().
+     * TODO: replace with throwing special exception from default test.
+     */
+    bool called_method_was_a_dummy_test_;
+
+private:
+
+    std::string current_test_name_;
+};
+
+namespace
+{
+
+/**
+ * Tests provided condition.
+ * Throws if false.
+ */
+void ensure(bool cond)
+{
+    if (!cond)
+    {
+        // TODO: default ctor?
+        throw failure("");
+    }
+}
+
+/**
+ * Tests provided condition.
+ * Throws if true.
+ */
+void ensure_not(bool cond)
+{
+    ensure(!cond);
+}
+
+/**
+ * Tests provided condition.
+ * Throws if false.
+ */
+template <typename T>
+void ensure(const T msg, bool cond)
+{
+    if (!cond)
+    {
+        throw failure(msg);
+    }
+}
+
+/**
+ * Tests provided condition.
+ * Throws if true.
+ */
+template <typename T>
+void ensure_not(const T msg, bool cond)
+{
+    ensure(msg, !cond);
+}
+
+/**
+ * Tests two objects for being equal.
+ * Throws if false.
+ *
+ * NB: both T and Q must have operator << defined somewhere, or
+ * client code will not compile at all!
+ */
+template <class T, class Q>
+void ensure_equals(const char* msg, const Q& actual, const T& expected)
+{
+    if (expected != actual)
+    {
+        std::stringstream ss;
+        ss << (msg ? msg : "") 
+            << (msg ? ":" : "") 
+            << " expected '" 
+            << expected 
+            << "' actual '" 
+            << actual
+            << '\'';
+        throw failure(ss.str().c_str());
+    }
+}
+
+template <class T, class Q>
+void ensure_equals(const Q& actual, const T& expected)
+{
+    ensure_equals<>(0, actual, expected);
+}
+
+/**
+ * Specialization of ensure_equals for double type.
+ * NOTE: unofficial extension added by mloskot
+ */
+template <>
+void ensure_equals<double, double>(const char* msg, const double& actual, const double& expected)
+{
+    const double epsilon = std::numeric_limits<double>::epsilon(); 
+    const double diff = actual - expected;
+
+    if ( !((diff <= epsilon) && (diff >= -epsilon )) )
+    {
+        std::stringstream ss;
+        ss << (msg?msg:"") << (msg?": ":"")
+            << std::scientific << std::showpoint << std::setprecision(16)
+            << "expected " << expected
+            << " actual " << actual
+            << " with precision " << epsilon;
+        throw failure(ss.str().c_str());
+    }
+}
+
+template <>
+void ensure_equals<double, double>(const double& actual, const double& expected)
+{
+    ensure_equals<>(0, actual, expected);
+}
+
+/**
+ * Tests two objects for being at most in given distance one from another.
+ * Borders are excluded.
+ * Throws if false.
+ *
+ * NB: T must have operator << defined somewhere, or
+ * client code will not compile at all! Also, T shall have
+ * operators + and -, and be comparable.
+ */
+template <class T>
+void ensure_distance(const char* msg, const T& actual, const T& expected,
+    const T& distance)
+{
+    if (expected-distance >= actual || expected+distance <= actual)
+    {
+        std::stringstream ss;
+        ss << (msg ? msg : "") 
+            << (msg? ":" : "") 
+            << " expected (" 
+            << expected-distance 
+            << " - "
+            << expected+distance 
+            << ") actual '" 
+            << actual
+            << '\'';
+        throw failure(ss.str().c_str());
+    }
+}
+
+template <class T>
+void ensure_distance(const T& actual, const T& expected, const T& distance)
+{
+    ensure_distance<>(0, actual, expected, distance);
+}
+
+/**
+ * Unconditionally fails with message.
+ */
+void fail(const char* msg = "")
+{
+    throw failure(msg);
+}
+
+} // end of namespace
+
+/**
+ * Walks through test tree and stores address of each
+ * test method in group. Instantiation stops at 0.
+ */
+template <class Test, class Group, int n>
+struct tests_registerer
+{
+    static void reg(Group& group)
+    {
+        group.reg(n, &Test::template test<n>);
+        tests_registerer<Test, Group, n - 1>::reg(group);
+    }
+};
+
+template <class Test, class Group>
+struct tests_registerer<Test, Group, 0>
+{
+    static void reg(Group&)
+    {
+    }
+};
+
+/**
+ * Test group; used to recreate test object instance for
+ * each new test since we have to have reinitialized 
+ * Data base class.
+ */
+template <class Data, int MaxTestsInGroup = 50>
+class test_group : public group_base
+{
+    const char* name_;
+
+    typedef void (test_object<Data>::*testmethod)();
+    typedef std::map<int, testmethod> tests;
+    typedef typename tests::iterator tests_iterator;
+    typedef typename tests::const_iterator tests_const_iterator;
+    typedef typename tests::const_reverse_iterator
+    tests_const_reverse_iterator;
+    typedef typename tests::size_type size_type;
+
+    tests tests_;
+    tests_iterator current_test_;
+
+    /**
+     * Exception-in-destructor-safe smart-pointer class.
+     */
+    template <class T>
+    class safe_holder
+    {
+        T* p_;
+        bool permit_throw_in_dtor;
+
+        safe_holder(const safe_holder&);
+        safe_holder& operator=(const safe_holder&);
+
+    public:
+        safe_holder() 
+            : p_(0),
+              permit_throw_in_dtor(false)
+        {
+        }
+
+        ~safe_holder()
+        {
+            release();
+        }
+
+        T* operator->() const
+        {
+            return p_;
+        }
+        
+        T* get() const
+        {
+            return p_;
+        }
+
+        /**
+         * Tell ptr it can throw from destructor. Right way is to
+         * use std::uncaught_exception(), but some compilers lack
+         * correct implementation of the function.
+         */
+        void permit_throw()
+        {
+            permit_throw_in_dtor = true;
+        }
+
+        /**
+         * Specially treats exceptions in test object destructor; 
+         * if test itself failed, exceptions in destructor
+         * are ignored; if test was successful and destructor failed,
+         * warning exception throwed.
+         */
+        void release()
+        {
+            try
+            {
+                if (delete_obj() == false)
+                {
+                    throw warning("destructor of test object raised"
+                        " an SEH exception");
+                }
+            }
+            catch (const std::exception& ex)
+            {
+                if (permit_throw_in_dtor)
+                {
+                    std::string msg = "destructor of test object raised"
+                        " exception: ";
+                    msg += ex.what();
+                    throw warning(msg);
+                }
+            }
+            catch( ... )
+            {
+                if (permit_throw_in_dtor)
+                {
+                    throw warning("destructor of test object raised an"
+                        " exception");
+                }
+            }
+        }
+
+        /**
+         * Re-init holder to get brand new object.
+         */
+        void reset()
+        {
+            release();
+            permit_throw_in_dtor = false;
+            p_ = new T();
+        }
+
+        bool delete_obj()
+        {
+#if defined(TUT_USE_SEH)
+            __try
+            {
+#endif
+                T* p = p_;
+                p_ = 0;
+                delete p;
+#if defined(TUT_USE_SEH)
+            }
+            __except(handle_seh_(::GetExceptionCode()))
+            {
+                if (permit_throw_in_dtor)
+                {
+                    return false;
+                }
+            }
+#endif
+            return true;
+        }
+    };
+
+public:
+
+    typedef test_object<Data> object;
+
+    /**
+     * Creates and registers test group with specified name.
+     */
+    test_group(const char* name)
+        : name_(name)
+    {
+        // register itself
+        runner.get().register_group(name_,this);
+
+        // register all tests
+        tests_registerer<object, test_group, MaxTestsInGroup>::reg(*this);
+    }
+
+    /**
+     * This constructor is used in self-test run only.
+     */
+    test_group(const char* name, test_runner& another_runner)
+        : name_(name)
+    {
+        // register itself
+        another_runner.register_group(name_, this);
+
+        // register all tests
+        tests_registerer<test_object<Data>, test_group, 
+            MaxTestsInGroup>::reg(*this);
+    };
+
+    /**
+     * Registers test method under given number.
+     */
+    void reg(int n, testmethod tm)
+    {
+        tests_[n] = tm;
+    }
+
+    /**
+     * Reset test position before first test.
+     */
+    void rewind()
+    {
+        current_test_ = tests_.begin();
+    }
+
+    /**
+     * Runs next test.
+     */
+    test_result run_next()
+    {
+        if (current_test_ == tests_.end())
+        {
+            throw no_more_tests();
+        }
+
+        // find next user-specialized test
+        safe_holder<object> obj;
+        while (current_test_ != tests_.end())
+        {
+            try
+            {
+                return run_test_(current_test_++, obj);
+            }
+            catch (const no_such_test&)
+            {
+                continue;
+            }
+        }
+
+        throw no_more_tests();
+    }
+
+    /**
+     * Runs one test by position.
+     */
+    test_result run_test(int n)
+    {
+        // beyond tests is special case to discover upper limit
+        if (tests_.rbegin() == tests_.rend())
+        {
+            throw beyond_last_test();
+        }
+        
+        if (tests_.rbegin()->first < n)
+        {
+            throw beyond_last_test();
+        }
+
+        // withing scope; check if given test exists
+        tests_iterator ti = tests_.find(n);
+        if (ti == tests_.end())
+        {
+            throw no_such_test();
+        }
+
+        safe_holder<object> obj;
+        return run_test_(ti, obj);
+    }
+
+private:
+
+    /**
+     * VC allows only one exception handling type per function,
+     * so I have to split the method.
+     * 
+     * TODO: refactoring needed!
+     */
+    test_result run_test_(const tests_iterator& ti, safe_holder<object>& obj)
+    {
+        std::string current_test_name;
+        try
+        {
+            if (run_test_seh_(ti->second,obj, current_test_name) == false)
+            {
+                throw seh("seh");
+            }
+        }
+        catch (const no_such_test&)
+        {
+            throw;
+        }
+        catch (const warning& ex)
+        {
+            // test ok, but destructor failed
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_,ti->first, current_test_name, 
+                test_result::warn, ex);
+            return tr;
+        }
+        catch (const failure& ex)
+        {
+            // test failed because of ensure() or similar method
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_,ti->first, current_test_name, 
+                test_result::fail, ex);
+            return tr;
+        }
+        catch (const seh& ex)
+        {
+            // test failed with sigsegv, divide by zero, etc
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_, ti->first, current_test_name, 
+                test_result::term, ex);
+            return tr;
+        }
+        catch (const bad_ctor& ex)
+        {
+            // test failed because test ctor failed; stop the whole group
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_, ti->first, current_test_name, 
+                test_result::ex_ctor, ex);
+            return tr;
+        }
+        catch (const std::exception& ex)
+        {
+            // test failed with std::exception
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_, ti->first, current_test_name, 
+                test_result::ex, ex);
+            return tr;
+        }
+        catch (...)
+        {
+            // test failed with unknown exception
+            if (obj.get())
+            {
+                current_test_name = obj->get_test_name();
+            }
+            test_result tr(name_, ti->first, current_test_name, 
+                test_result::ex);
+            return tr;
+        }
+
+        // test passed
+        test_result tr(name_,ti->first, current_test_name, test_result::ok);
+        return tr;
+    }
+
+    /**
+     * Runs one under SEH if platform supports it.
+     */
+    bool run_test_seh_(testmethod tm, safe_holder<object>& obj, 
+        std::string& current_test_name)
+    {
+#if defined(TUT_USE_SEH)
+        __try
+        {
+#endif
+        if (obj.get() == 0)
+        {
+            reset_holder_(obj);
+        }
+            
+        obj->called_method_was_a_dummy_test_ = false;
+
+#if defined(TUT_USE_SEH)
+
+            __try
+            {
+#endif
+                (obj.get()->*tm)();
+#if defined(TUT_USE_SEH)
+            }
+            __except(handle_seh_(::GetExceptionCode()))
+            {
+                // throw seh("SEH");
+                current_test_name = obj->get_test_name();
+                return false;
+            }
+#endif
+
+        if (obj->called_method_was_a_dummy_test_)
+        {
+            // do not call obj.release(); reuse object
+            throw no_such_test();
+        }
+
+        current_test_name = obj->get_test_name();
+        obj.permit_throw();
+        obj.release();
+#if defined(TUT_USE_SEH)
+        }
+        __except(handle_seh_(::GetExceptionCode()))
+        {
+            return false;
+        }
+#endif
+        return true;
+    }
+
+    void reset_holder_(safe_holder<object>& obj)
+    {
+        try
+        {
+            obj.reset();
+        }
+        catch (const std::exception& ex)
+        {
+            throw bad_ctor(ex.what());
+        }
+        catch (...)
+        {
+            throw bad_ctor("test constructor has generated an exception;"
+                " group execution is terminated");
+        }
+    }
+};
+
+#if defined(TUT_USE_SEH)
+/**
+ * Decides should we execute handler or ignore SE.
+ */
+inline int handle_seh_(DWORD excode)
+{
+    switch(excode)
+    {
+    case EXCEPTION_ACCESS_VIOLATION:
+    case EXCEPTION_DATATYPE_MISALIGNMENT:
+    case EXCEPTION_BREAKPOINT:
+    case EXCEPTION_SINGLE_STEP:
+    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+    case EXCEPTION_FLT_DENORMAL_OPERAND:
+    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+    case EXCEPTION_FLT_INEXACT_RESULT:
+    case EXCEPTION_FLT_INVALID_OPERATION:
+    case EXCEPTION_FLT_OVERFLOW:
+    case EXCEPTION_FLT_STACK_CHECK:
+    case EXCEPTION_FLT_UNDERFLOW:
+    case EXCEPTION_INT_DIVIDE_BY_ZERO:
+    case EXCEPTION_INT_OVERFLOW:
+    case EXCEPTION_PRIV_INSTRUCTION:
+    case EXCEPTION_IN_PAGE_ERROR:
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+    case EXCEPTION_STACK_OVERFLOW:
+    case EXCEPTION_INVALID_DISPOSITION:
+    case EXCEPTION_GUARD_PAGE:
+    case EXCEPTION_INVALID_HANDLE:
+        return EXCEPTION_EXECUTE_HANDLER;
+    };
+
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+}
+
+#endif
+
diff -urN liblas-1.2.1/test/unit/tut/tut_reporter.hpp main/test/unit/tut/tut_reporter.hpp
--- liblas-1.2.1/test/unit/tut/tut_reporter.hpp	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/tut/tut_reporter.hpp	2009-10-02 16:46:36.000000000 +0200
@@ -0,0 +1,227 @@
+#ifndef TUT_REPORTER
+#define TUT_REPORTER
+
+#include <tut/tut.hpp>
+
+/**
+ * Template Unit Tests Framework for C++.
+ * http://tut.dozen.ru
+ *
+ * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com
+ */
+namespace
+{
+    
+std::ostream& operator<<(std::ostream& os, const tut::test_result& tr)
+{
+    switch(tr.result)
+    {
+    case tut::test_result::ok:
+        os << '.';
+        break;
+    case tut::test_result::fail:
+        os << '[' << tr.test << "=F]";
+        break;
+    case tut::test_result::ex_ctor:
+        os << '[' << tr.test << "=C]";
+        break;
+    case tut::test_result::ex:
+        os << '[' << tr.test << "=X]";
+        break;
+    case tut::test_result::warn:
+        os << '[' << tr.test << "=W]";
+        break;
+    case tut::test_result::term:
+        os << '[' << tr.test << "=T]";
+        break;
+    }
+
+    return os;
+}
+
+} // end of namespace
+
+namespace tut
+{
+
+/**
+ * Default TUT callback handler.
+ */
+class reporter : public tut::callback
+{
+    std::string current_group;
+    typedef std::vector<tut::test_result> not_passed_list;
+    not_passed_list not_passed;
+    std::ostream& os;
+
+public:
+
+    int ok_count;
+    int exceptions_count;
+    int failures_count;
+    int terminations_count;
+    int warnings_count;
+
+    reporter() 
+        : os(std::cout)
+    {
+        init();
+    }
+
+    reporter(std::ostream& out) 
+        : os(out)
+    {
+        init();
+    }
+
+    void run_started()
+    {
+        init();
+    }
+
+    void test_completed(const tut::test_result& tr)
+    {
+        if (tr.group != current_group)
+        {
+            os << std::endl << tr.group << ": " << std::flush;
+            current_group = tr.group;
+        }
+
+        os << tr << std::flush;
+        if (tr.result == tut::test_result::ok)
+        {
+            ok_count++;
+        }
+        else if (tr.result == tut::test_result::ex)
+        {
+            exceptions_count++;
+        }
+        else if (tr.result == tut::test_result::ex_ctor)
+        {
+            exceptions_count++;
+        }
+        else if (tr.result == tut::test_result::fail)
+        {
+            failures_count++;
+        }
+        else if (tr.result == tut::test_result::warn)
+        {
+            warnings_count++;
+        }
+        else
+        {
+            terminations_count++;
+        }
+
+        if (tr.result != tut::test_result::ok)
+        {
+            not_passed.push_back(tr);
+        }
+    }
+
+    void run_completed()
+    {
+        os << std::endl;
+
+        if (not_passed.size() > 0)
+        {
+            not_passed_list::const_iterator i = not_passed.begin();
+            while (i != not_passed.end())
+            {
+                tut::test_result tr = *i;
+
+                os << std::endl;
+
+                os << "---> " << "group: " << tr.group
+                << ", test: test<" << tr.test << ">"
+                << (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string())
+                << std::endl;
+
+                os << "     problem: ";
+                switch(tr.result)
+                {
+                case test_result::fail:
+                    os << "assertion failed" << std::endl;
+                    break;
+                case test_result::ex:
+                case test_result::ex_ctor:
+                    os << "unexpected exception" << std::endl;
+                    if( tr.exception_typeid != "" )
+                    {
+                        os << "     exception typeid: "
+                        << tr.exception_typeid << std::endl;
+                    }
+                    break;
+                case test_result::term:
+                    os << "would be terminated" << std::endl;
+                    break;
+                case test_result::warn:
+                    os << "test passed, but cleanup code (destructor) raised"
+                        " an exception" << std::endl;
+                    break;
+                default:
+                    break;
+                }
+
+                if (!tr.message.empty())
+                {
+                    if (tr.result == test_result::fail)
+                    {
+                        os << "     failed assertion: \"" << tr.message << "\"" 
+                            << std::endl;
+                    }
+                    else
+                    {
+                        os << "     message: \"" << tr.message << "\"" 
+                            << std::endl;
+                    }
+                }
+
+                ++i;
+            }
+        }
+
+        os << std::endl;
+
+        os << "tests summary:";
+        if (terminations_count > 0)
+        {
+            os << " terminations:" << terminations_count;
+        }
+        if (exceptions_count > 0)
+        {
+            os << " exceptions:" << exceptions_count;
+        }
+        if (failures_count > 0)
+        {
+            os << " failures:" << failures_count;
+        }
+        if (warnings_count > 0)
+        {
+            os << " warnings:" << warnings_count;
+        }
+        os << " ok:" << ok_count;
+        os << std::endl;
+    }
+
+    bool all_ok() const
+    {
+        return not_passed.empty();
+    }
+
+private:
+
+    void init()
+    {
+        ok_count = 0;
+        exceptions_count = 0;
+        failures_count = 0;
+        terminations_count = 0;
+        warnings_count = 0;
+        not_passed.clear();
+    }
+};
+
+}
+
+#endif
diff -urN liblas-1.2.1/test/unit/tut/tut_restartable.hpp main/test/unit/tut/tut_restartable.hpp
--- liblas-1.2.1/test/unit/tut/tut_restartable.hpp	1970-01-01 01:00:00.000000000 +0100
+++ main/test/unit/tut/tut_restartable.hpp	2009-10-02 16:46:36.000000000 +0200
@@ -0,0 +1,394 @@
+#ifndef TUT_RESTARTABLE_H_GUARD
+#define TUT_RESTARTABLE_H_GUARD
+
+#include <tut/tut.hpp>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+
+/**
+ * Template Unit Tests Framework for C++.
+ * http://tut.dozen.ru
+ *
+ * Optional restartable wrapper for test_runner. Allows to restart test runs
+ * finished due to abnormal test application termination (such as segmentation
+ * fault or math error).
+ *
+ * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com
+ */
+
+namespace tut
+{
+    
+namespace util
+{
+    
+/**
+ * Escapes non-alphabetical characters in string.
+ */
+std::string escape(const std::string& orig)
+{
+    std::string rc;
+    std::string::const_iterator i,e;
+    i = orig.begin();
+    e = orig.end();
+
+    while (i != e)
+    {
+        if ((*i >= 'a' && *i <= 'z') ||
+                (*i >= 'A' && *i <= 'Z') ||
+                (*i >= '0' && *i <= '9') )
+        {
+            rc += *i;
+        }
+        else
+        {
+            rc += '\\';
+            rc += ('a'+(((unsigned int)*i) >> 4));
+            rc += ('a'+(((unsigned int)*i) & 0xF));
+        }
+
+        ++i;
+    }
+    return rc;
+}
+
+/**
+ * Un-escapes string.
+ */
+std::string unescape(const std::string& orig)
+{
+    std::string rc;
+    std::string::const_iterator i,e;
+    i = orig.begin();
+    e = orig.end();
+
+    while (i != e)
+    {
+        if (*i != '\\')
+        {
+            rc += *i;
+        }
+        else
+        {
+            ++i;
+            if (i == e)
+            {
+                throw std::invalid_argument("unexpected end of string");
+            }
+            unsigned int c1 = *i;
+            ++i;
+            if (i == e)
+            {
+                throw std::invalid_argument("unexpected end of string");
+            }
+            unsigned int c2 = *i;
+            rc += (((c1 - 'a') << 4) + (c2 - 'a'));
+        }
+
+        ++i;
+    }
+    return rc;
+}
+
+/**
+ * Serialize test_result avoiding interfering with operator <<.
+ */
+void serialize(std::ostream& os, const tut::test_result& tr)
+{
+    os << escape(tr.group) << std::endl;
+    os << tr.test << ' ';
+    switch(tr.result)
+    {
+    case test_result::ok:
+        os << 0;
+        break;
+    case test_result::fail:
+        os << 1;
+        break;
+    case test_result::ex:
+        os << 2;
+        break;
+    case test_result::warn:
+        os << 3;
+        break;
+    case test_result::term:
+        os << 4;
+        break;
+    default:
+        throw std::logic_error("operator << : bad result_type");
+    }
+    os << ' ' << escape(tr.message) << std::endl;
+}
+
+/**
+ * deserialization for test_result
+ */
+void deserialize(std::istream& is, tut::test_result& tr)
+{
+    std::getline(is,tr.group);
+    if (is.eof())
+    {
+        throw tut::no_more_tests();
+    }
+    tr.group = unescape(tr.group);
+
+    tr.test = -1;
+    is >> tr.test;
+    if (tr.test < 0)
+    {
+        throw std::logic_error("operator >> : bad test number");
+    }
+
+    int n = -1;
+    is >> n;
+    switch(n)
+    {
+    case 0:
+        tr.result = test_result::ok;
+        break;
+    case 1:
+        tr.result = test_result::fail;
+        break;
+    case 2:
+        tr.result = test_result::ex;
+        break;
+    case 3:
+        tr.result = test_result::warn;
+        break;
+    case 4:
+        tr.result = test_result::term;
+        break;
+    default:
+        throw std::logic_error("operator >> : bad result_type");
+    }
+
+    is.ignore(1); // space
+    std::getline(is,tr.message);
+    tr.message = unescape(tr.message);
+    if (!is.good())
+    {
+        throw std::logic_error("malformed test result");
+    }
+}
+};
+
+/**
+ * Restartable test runner wrapper.
+ */
+class restartable_wrapper
+{
+    test_runner& runner_;
+    callback* callback_;
+
+    std::string dir_;
+    std::string log_; // log file: last test being executed
+    std::string jrn_; // journal file: results of all executed tests
+
+public:
+    /**
+     * Default constructor.
+     * @param dir Directory where to search/put log and journal files
+     */
+    restartable_wrapper(const std::string& dir = ".")
+        : runner_(runner.get()), 
+          callback_(0), 
+          dir_(dir)
+    {
+        // dozen: it works, but it would be better to use system path separator
+        jrn_ = dir_ + '/' + "journal.tut";
+        log_ = dir_ + '/' + "log.tut";
+    }
+
+    /**
+     * Stores another group for getting by name.
+     */
+    void register_group(const std::string& name, group_base* gr)
+    {
+        runner_.register_group(name,gr);
+    }
+
+    /**
+     * Stores callback object.
+     */
+    void set_callback(callback* cb)
+    {
+        callback_ = cb;
+    }
+
+    /**
+     * Returns callback object.
+     */
+    callback& get_callback() const
+    {
+        return runner_.get_callback();
+    }
+
+    /**
+     * Returns list of known test groups.
+     */
+    groupnames list_groups() const
+    {
+        return runner_.list_groups();
+    }
+
+    /**
+     * Runs all tests in all groups.
+     */
+    void run_tests() const
+    {
+        // where last run was failed
+        std::string fail_group;
+        int fail_test;
+        read_log_(fail_group,fail_test);
+        bool fail_group_reached = (fail_group == "");
+
+        // iterate over groups
+        tut::groupnames gn = list_groups();
+        tut::groupnames::const_iterator gni,gne;
+        gni = gn.begin();
+        gne = gn.end();
+        while (gni != gne)
+        {
+            // skip all groups before one that failed
+            if (!fail_group_reached)
+            {
+                if (*gni != fail_group)
+                {
+                    ++gni;
+                    continue;
+                }
+                fail_group_reached = true;
+            }
+
+            // first or restarted run
+            int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1;
+            while(true)
+            {
+                // last executed test pos
+                register_execution_(*gni,test);
+
+                try
+                {
+                    tut::test_result tr = runner_.run_test(*gni,test);
+                    register_test_(tr);
+                }
+                catch (const tut::beyond_last_test&)
+                {
+                    break;
+                }
+                catch(const tut::no_such_test&)
+                {
+                    // it's ok
+                }
+
+                ++test;
+            }
+
+            ++gni;
+        }
+
+        // show final results to user
+        invoke_callback_();
+
+        // truncate files as mark of successful finish
+        truncate_();
+    }
+
+private:
+    /**
+     * Shows results from journal file.
+     */
+    void invoke_callback_() const
+    {
+        runner_.set_callback(callback_);
+        runner_.get_callback().run_started();
+
+        std::string current_group;
+        std::ifstream ijournal(jrn_.c_str());
+        while (ijournal.good())
+        {
+            // read next test result
+            try
+            {
+                tut::test_result tr;
+                util::deserialize(ijournal,tr);
+                runner_.get_callback().test_completed(tr);
+            }
+            catch (const no_more_tests&)
+            {
+                break;
+            }
+        }
+
+        runner_.get_callback().run_completed();
+    }
+
+    /**
+     * Register test into journal.
+     */
+    void register_test_(const test_result& tr) const
+    {
+        std::ofstream ojournal(jrn_.c_str(), std::ios::app);
+        util::serialize(ojournal, tr);
+        ojournal << std::flush;
+        if (!ojournal.good())
+        {
+            throw std::runtime_error("unable to register test result in file "
+                + jrn_);
+        }
+    }
+
+    /**
+     * Mark the fact test going to be executed
+     */
+    void register_execution_(const std::string& grp, int test) const
+    {
+        // last executed test pos
+        std::ofstream olog(log_.c_str());
+        olog << util::escape(grp) << std::endl << test << std::endl << std::flush;
+        if (!olog.good())
+        {
+            throw std::runtime_error("unable to register execution in file "
+                + log_);
+        }
+    }
+
+    /**
+     * Truncate tests.
+     */
+    void truncate_() const
+    {
+        std::ofstream olog(log_.c_str());
+        std::ofstream ojournal(jrn_.c_str());
+    }
+
+    /**
+     * Read log file
+     */
+    void read_log_(std::string& fail_group, int& fail_test) const
+    {
+        // read failure point, if any
+        std::ifstream ilog(log_.c_str());
+        std::getline(ilog,fail_group);
+        fail_group = util::unescape(fail_group);
+        ilog >> fail_test;
+        if (!ilog.good())
+        {
+            fail_group = "";
+            fail_test = -1;
+            truncate_();
+        }
+        else
+        {
+            // test was terminated...
+            tut::test_result tr(fail_group, fail_test, "", tut::test_result::term);
+            register_test_(tr);
+        }
+    }
+};
+
+}
+
+#endif
+
