# -*- coding: utf-8 -*-
=======
CHANGES
=======

Release 0.15.0 (2014-07-01)
---------------------------

* [enhance] oktest.web.WSGITest class supports multipart form data.

    ## build multipart data
    from oktest.web import MultiPart
    mp = MultiPart()    # or boundary='abcdef'; mp = MutliPart(boundary)
    mp.add("name1", "value1")          # add string value
    with open("logo.png", 'wb') as f:  # add file value
        mp.add("file1", f.read(), "logo.png", "image/png")
    ## test with multipart data
    from oktest.web import WSGITest
    http = WSGITest(wsgi_app)
    resp = http.POST('/upload', multipart=mp)  # or params=mp
    ok (resp).is_response(200)

* [enhance] oktest.web.WSGITest class supports 'Cookie' and 'Set-Cookie'.

    from oktest.web import WSGITest
    http = WSGITest(wsgi_app)
    ## request: 'Cookie' header
    resp = http.GET('/', cookies='name=value')  # or cookies={'name':'value'}
    ## response: 'Set-Cookie' header
    ok (resp).is_response(200).cookie('name', 'value')
    ok (resp).is_response(200).cookie('name', re.compile(r'^value$'),
                                      domain='www.example.com',
                                      path='/cgi'
                                      expires='Wed, 01-Jan-2020 12:34:56 GMT',
                                      max_age='1200',
                                      secure=True,
                                      httponly=True)

* [enhance] New assertion methods.

    ok (xs).all(lambda x: x is None)       # ok when all items in xs are None
    ok (xs).any(lambda x: x is None)       # ok when there is None in xs
    ok (x).between(minval, maxval)         # ok when minval <= x <= maxval
    ok (xs).length([minlen, maxlen])       # ok when minlen <= len(xs) <= maxlen
    ok (dictionary).has_key('key')         # ok when dictinary has key
    ok (dictionary).has_item('key','val')  # ok when dictionary has key an val

* [enhance] New utility function 'options_of()' to get user-defined options.
  ex:

    import unittest
    from oktest import ok, test, options_of

    class FooTest(unittest.TestCase):

        def setUp(self):
            ## change setUp() behaviour according to tag
            dictionary = options_of(self)
            if dictionary.get('tag') == "experimental":
                ....

        @test("example", tag="experimental", num=123)
        def _(self):
            assert options_of(self) == {'tag': "experimental", 'num': 123}

* [bugfix] oktest.web.WSGITest now works on Python 3.4.

* [bugfix] fix oktest.web.WSGITest class to encode urlpath when multibyte.


Release 0.14.2 (2014-03-20)
---------------------------

* [bugfix] Avoids unicode error on environments that sys.stdout.encoding
  is 'ISO-8859-1' or 'ANSI_X3.4-1968'.


Release 0.14.1 (2014-03-11)
---------------------------

* [enhance] WSGITest class supports `params' parameter.
  Example::

      from oktest.web import WSGITest
      http = WSGITest(app)
      resp = http.GET('/', params={'x':'1'})   # same as http.GET('/', query={'x':'1'})
      resp = http.POST('/', params={'x':'1'})  # same as http.GET('/', form={'x':'1'})


Release 0.14.0 (2014-03-10)
---------------------------

* [enhance] Response object returned by `WSGITest#GET()' or '#POST()' now
  supports `body_json' property.
  Example::

      from oktest.web import WSGITest
      http = WSGITest(app)
      resp = http.GET('/')
      print(resp.body_json)

* [change] `headers` argument of `WSGITest#GET()' (or '#POST()' and so on)
  now means HTTP headers, not environ values.
  Example::

      ## version <= 0.13
      http.GET('/', headers={'HTTP_COOKIE': 'name=val'})

      ## version >= 0.14
      http.GET('/', headers={'Cookie': 'name=val'})
      ## or
      http.GET('/', environ={'HTTP_COOKIE': 'name=val'})

* [enhance] (Experimental) `oktest.validator.Validator' class is added.
  It is convenient to test complex data structure.
  Example::

      from oktest.validator import Validator as V
      ok (resp.body_json) == {
        "status": "OK",
        "member": {
          "name":     "Haruhi",
          "gender":   V('gender', enum=('F', 'M')),
          "age":      V('age', type=int, between=(15, 18)),
          "birthday": V('created_at', pattern=r'^\d\d\d\d-\d\d-\d\d$')
        }
      }

  See users guide for details.
  http://www.kuwata-lab.com/oktest/oktest-py_users-guide.html#validator



Release 0.13.0 (2014-01-23)
---------------------------

* [enhance] `ok().is_response()' now supports Requests.
  Example::

      import requests
      resp = requests.get('http://www.example.com/')
      ok (resp).is_response(200, 'text/html')

* [enhance] (Experimental) Add 'oktest.web' module to help WSGI app testing.
  Example::

      ## create WSGI application
      class App(object):
          def __call__(self, environ, start_response):
              status  = '200 OK'
              headers = [('Content-Type', 'application/json')]
              body    = [b'''{"message":"Hello!"}''']  # bytes, not unicode
              start_response(status, headers)
              return body

      app = App()

      ## test for app
      import unittest
      import oktest
      from oktest import test, ok, subject
      from oktest.web import WSGITest           # !!!!!

      http  = WSGITest(app)                     # !!!!!
      https = WSGITest(app, {'HTTPS': 'on'})    # !!!!!

      class AppTest(unittest.TestCase):

          with subject('GET /'):

              @test("Returns messaging JSON.")
              def _(self):
                  resp = http.GET('/')     # or http('GET', '/')
                  ok (resp).is_response(200).json({"message": "Hello!"})
                  ## or
                  status, headers, body = http.GET('/')   # or http('GET', '/')
                  ok (status)  == '200 OK'
                  ok (headers) == [('Content-Type', 'application/json')]
                  ok (body)    == [b'''{"message":"Hello!"}''']

      if __name__ == '__main__':
          oktest.main()



Release 0.12.1 (2014-01-20)
---------------------------

* [bugfix] `ok()' object now doesn't have http response assertions.
  You must call `ok().is_response()' at first to assert response object. ::

      hasattr(ok(response).is_response(), 'json')   # True
      hasattr(ok(response), 'json')   # True on 0.12.0, False on 0.12.1

* [bugfix] `ok().should' now allows method chain.
  ex::

      ok ("image001.jpg").should.startswith('image').endswith(('.jpg', '.png'))



Release 0.12.0 (2014-01-12)
---------------------------

* [enhance] `ok (actual) == expected' now prints difference between
  actual and expected values with `pprint.pformat()' when values are
  one of list, tuple, or dict.
  ex::

    class ExampleTest(unittest.TestCase):
      def test_ex1(self):
        expected = { 'username': "Haruhi", 'gender': "Female",
                     'email': "haruhi@sos-brigade.org", }
        actual   = { 'username': "Haruhi", 'gender': "female",
                     'email': "haruhi@sos-brigade.org", }
        ok (actual) == expected
    #
    if __name__ == "__main__":
      oktest.main()

  Above test script reports such as::

    AssertionError:
    --- expected
    +++ actual
    @@ -1,3 +1,3 @@
     {'email': 'haruhi@sos-brigade.org',
    - 'gender': 'Female',
    + 'gender': 'female',
      'username': 'Haruhi'}

* [enhance] @at_end decorator registers callback which is invoked after test.
  This is similar to tearDown() method, but more flexible than it.
  ex::

    from oktest import at_end

    class HomhomTest(unittest.TestCase):
      def test1(self):
        ## create dummy file
        tmpfile = 'dummy.txt'
        with open(tmpfile, 'w') as f:
          f.write("blablabla")
        ## register callback to delete dummy file at end of test case
        @at_end
        def _():
          os.unlink(tmpfile)
        ## do test
        with open(tmpfile) as f:
          ok (f.read()) == "blablabla"

  You can use @at_end instead of fixture release functions.
  ex::

    class HomhomTest(unittest.TestCase):

      ##
      ## fixture provider -- use @at_end instead of releaser
      ##
      def provide_tmpfile(self):
        ## create dummy file
        tmpfile = 'dummy.txt'
        with open(tmpfile, 'w') as f:
          f.write('blablabla')
        ## register callback to delete dummy file at end of test case
        @at_end
        def _():
          os.unlink(tmpfile)
        ## return fixture data
        return tmpfile

      ##
      ## fixture releaser -- no need to define because we have @at_end!
      ##
      #def release_tmpfile(self, tmpfile):
      #  os.unlink(tmpfile)

  @at_end decorator is similar to unittest.TestCase#atCleanup(),
  but the former is called *before* tearDown() and the latter is called
  *after* tearDown().

* [enhance] (experimental) New assertion ``ok(response).is_response()``
  to assert WebOb or Werkzeug resonse object.
  ex::

    ok (response).is_response(200)                          # status code
    ok (response).is_response((302, 303))                   # status code
    ok (response).is_response('200 OK')                     # status line
    ok (response).is_response(200, 'image/jpeg')            # content-type
    ok (response).is_response(200, re.compile(r'^image/(jpeg|png|gif)$'))
    ok (response).is_response(302).header("Location", "/")  # header
    ok (response).is_response(200).json({"status": "OK"})   # json data
    ok (response).is_response(200).body("<h1>Hello</h1>")   # response body
    ok (response).is_response(200).body(re.compile("<h1>.*?</h1>"))

* [enhance] ``ok(x).is_truthy()`` tests whether ``bool(x) == True``.
  This is similar to ``ok(bool(x)) == True`` but reports ``x`` value
  instead of True/False when assertion failed.

* [enhance] ``ok(x).is_falsy()`` tests whether ``bool(x) == False``.
  This is similar to ``ok(bool(x)) == False`` but reports ``x`` value
  instead of True/False when assertion failed.

* [enhance] 'oktest.util.from_here()' is defined which adds current
  path into sys.path temporarily.
  This is useful very much when you want to import a certain module
  from current directory or a specific directory.
  ex::

    from oktest.util import from_here
    with from_here():
      import mymodule1       # import from directory path of this file
    with from_here('../lib'):
      import mymodule2       # import from ../lib

* [enhance] 'oktest.util.randstr(n)' is defined which returns random
  number string. Width of returned string is n (default 8).
  This is very useful when creating fixture data.
  ex::

    >>> from oktest.util import randstr
    >>> randstr(4)
    '7327'
    >>> randstr(4)
    '1598'
    >>> randstr(4)
    '0362'
    >>> randstr()
    '38127841'

* [enhance] subject() and situation() now accept user-defined tags.
  ex::

    class FooTest(unitest.TestCase):
      with subject('#method1()', category='basic'):
        with situation('when argument is None', category='advanced'):
          @test('returns True')
          def _(self):
	    ok (Foo().method1('')) == True

* [enhance] @test decorator regards '[!xxx]' in description as spec id.
  ex::

    ## python
    class HomhomTest(unittest.TestCase):
      @test('[!bk201] 1+1 should be 2')    # spec id is 'bk201'
      def _(self):
        ok (1+1) == 2
      @test('[!nov11] 1-1 should be 0')    # spec id is 'nov11'
      def _(self):
        ok (1-1) == 0

  You can filter tests by spec id (sid).

    ## command-line
    bash$ python -m oktest test/example_test.py -f sid=bk201

* [enhance] multiple errors are reported.
  For example, if you got error on test method and tearDown(),
  both errors are reported.

* [change] '[passed]', '[Failed]', and '[skipped]' are renamed to
  '[pass]', '[Fail]', '[skip]' respectively.

  Previous output::

    - [passed] 1+1 should be 2.
    - [Failed] 1-1 should be 0.
    ## total:1, passed:0, failed:0, error:0, skipped:0, todo:1  (0.000 sec)

  New version output::

    - [pass] 1+1 should be 2.
    - [Fail] 1-1 should be 0.
    ## total:1, pass:0, fail:0, error:0, skip:0, todo:1  (0.000 sec)

* [bugfix] @test decorator now supports unicode description.
  ex::

    @test(u"日本語")    # error on previous version but not in this release
    def _(self):
      ok (1+1) == 2

* [bugfix] @todo decorator now supports fixture arguments.
  ex::

    class FooTest(unittest.TestCase):
      #
      def provide_x(self):
        return 123
      #
      @test('example')
      @todo             # error on previous version but not on this release
      def _(self, x):
        assert False


Release 0.11.1
--------------

* [bugfix] fix '-s verbose' (verbose mode) option to clear long test description.

* [bugfix] fix test reporter not to raise UnicodeEncodeError/UnicodeDecodeError.


Release 0.11.0
--------------

* [change] 'spec()' is now NOT obsoleted.

* [change] 'spec()' is now available as function decorator.
  ex::

    class FooTest(unittest.TestCase):
      def test_method1(self)
        @spec("1+1 should be 2")
	def _():
	  ok (1+1) == 2
        @spec("1-1 should be 0")
	def _():
	  ok (1-1) == 0

* [enhance] New assertions: not_file(), not_dir() and not_exist().
  ex::

    ok (".").not_file()         # same as NG (".").is_file()
    ok (__file__).not_dir()     # same as NG (__file__).is_dir()
    ok ("foobar").not_exist()   # same as NG ("foobar").exists()

* [enhance] New assertion: not_match().
  ex::

    ok ("SOS").not_match(r"\d+")  # same as NG ("SOS").matches(r"\d+")

* [enhance] Global provider/releaser functions can take 'self' argument.
  ex::

    def provide_logname(self):
        self._LOGNAME = os.getenv('LOGNAME')
	os.environ['LOGNAME'] = "Haruhi"
	return os.environ['LOGNAME']

    def release_logname(self, value):
        os.environ['LOGNAME'] = self._LOGNAME

* [change] Change not to ignore test classes which name starts with '_'.

* [change] (internal) Move some utility functions to 'util' module.

* [change] (internal) Move '_Context' and '_RunnableContext' classes into 'util' module.

* [change] (internal) Move 'Color' class into 'util' module

* [change] (internal) Remove 'OUT' variable in 'Reporter' class

* [change] (internal) Move 'TARGET_PATTERN' variable to 'config'

* [bugfix] Fix to clear ImportError after trying to import unittest2


Release 0.10.0
--------------

* [change] 'oktest.spec()' is obsoleted completely.
  It will print warning message if you use it.

* [change] 'oktest.helper' module is renamed to 'oktest.util'.
  ('oktest.helper' is still available for backward compabibility.)

* [enhance] Add 'oktest.main()' which is a replacement of 'oktest.run()'.
  Using 'oktest.main()' instead of 'oktest.run()', command options are available.
  ex::

    ## for example:
    $ python test/foobar_test.py -sp -f test='*keyword*'
    ## is almost same as:
    $ python -m oktest test/foobar_test.py -sp -f test='*keyword*'

* [enhance] Add 'oktest.fail(message)' which is same as 'unittest.fail(message)'.
  ex::

    from oktest import fail
    fail("not impelmented yet")    # will raise AssertionError

* [enhance] (Experimental) Add '@todo' decorator which is equivarent to
  '@unittest.expectedFailure'.
  ex::

    from oktest import ok, test, todo

    def add(x, y):
        return 0      # not implemented yet!

    class AddTest(unittest.TestCase):
        @test("returns sum of arguments.")
	@todo         # equivarent to @unittest.expectedFailure
        def _(self):
	    ok (10, 20) == 30   ## will be failed expectedly
	                        ## (because not implemented yet)

  Expected failure of assertion is reported as '[TODO]', not '[Failed]'.

* [enhance] (Experimental) Test context supported.
  It helps you to describe specification in structured style.
  ex::

    from oktest import ok, test
    from oktest import subject, situation

    class SampleTestCase(unittest.TestCase):
      SUBJECT = "class 'Sample'"

      with subject("method1()"):

        with situation("when condition:"):

          @test("spec1")
            def _(self):
            ...

          @test("spec2")
          def _(self):
            ...

        with situation("else:"):

          @test("spec3")
          def _(self):
            ...

    if __name__ == '__main__':
        import oktest
        oktest.main()

  Output exmple::

    $ python test/example_test.py
    * class 'Sample'
      + method1()
        + when condition:
	  - [passed] spec1
	  - [passed] spec2
        + else:
	  - [passed] spec3
    ## total:3, passed:3, failed:0, error:0, skipped:0, todo:0  (0.000 sec)

* [change] Output is changed.

    ###
    ### previous version
    ###
    $ python test/foo_test.py
    * FooTest
      - [ok] test1
      - [ok] test2
      - [skipped] test3
    ## total:3, passed:2, failed:0, error:0, skipped:1   (elapsed 0.000)

    ###
    ### in this release
    ###
    $ python test/foo_test.py
    * FooTest
      - [passed] test1
      - [passed] test2
      - [skipped] test3 (reason: REASON)
    ## total:3, passed:2, failed:0, error:0, skipped:1, todo:0  (0.000 sec)


Release 0.9.0
-------------

* New '@test' decorator provided. It is simple but very powerful.
  Using @test decorator, you can write test description in free text
  instead of test method.
  ex::

    class FooTest(unittest.TestCase):

        def test_1_plus_1_should_be_2(self):  # not cool...
            self.assertEqual(2, 1+1)

        @test("1 + 1 should be 2")    # cool! easy to read & write!
        def _(self):
            self.assertEqual(2, 1+1)

* Fixture injection support by '@test' decorator.
  Arguments of test method are regarded as fixture names and
  they are injected by @test decorator automatically.
  Instance methods or global functions which name is 'provide_xxxx' are
  regarded as fixture provider (or builder) for fixture 'xxxx'.
  ex::

    class SosTest(unittest.TestCase):

        ##
        ## fixture providers.
        ##
        def provide_member1(self):
            return {"name": "Haruhi"}

        def provide_member2(self):
            return {"name": "Kyon"}

        ##
        ## fixture releaser (optional)
        ##
        def release_member1(self, value):
            assert value == {"name": "Haruhi"}

        ##
        ## testcase which requires 'member1' and 'member2' fixtures.
        ##
        @test("validate member's names")
        def _(self, member1, member2):
            assert member1["name"] == "Haruhi"
            assert member2["name"] == "Kyon"

  Dependencies between fixtures are resolved automatically.
  ex::

    class BarTest(unittest.TestCase):

        ##
        ## for example:
        ## - Fixture 'a' depends on 'b' and 'c'.
        ## - Fixture 'c' depends on 'd'.
        ##
        def provide_a(b, c):  return b + c + ["A"]
        def provide_b():      return ["B"]
        def provide_c(d):     return d + ["C"]
        def provide_d():      reutrn ["D"]

        ##
        ## Dependencies between fixtures are solved automatically.
        ##
        @test("dependency test")
        def _(self, a):
            assert a == ["B", "D", "C", "A"]

  If loop exists in dependency then @test reports error.

  If you want to integrate with other fixture library, see the following
  example::

      class MyFixtureManager(object):
          def __init__(self):
              self.values = { "x": 100, "y": 200 }
          def provide(self, name):
              return self.values[name]
          def release(self, name, value):
              pass

      oktest.fixure_manager = MyFixtureResolver()

* Supports command-line interface to execute test scripts.
  ex::

    ## run test scripts except foo_*.py in plain style
    $ python -m oktest -x 'foo_*.py' -sp tests/*_test.py
    ## run test scripts in 'tests' dir with pattern '*_test.py'
    $ python -m oktest -p '*_test.py' tests
    ## filter by class name
    $ python -m oktest -f class='ClassName*' tests
    ## filter by test method name
    $ python -m oktest -f test='*keyword*' tests
    ## filter by user-defined option added by @test decorator
    $ python -m oktest -f tag='*value*' tests

  Try ``python -m oktest -h`` for details about command-line options.

* Reporting style is changed. Oktest now provides three reporing styles.
  - plain (similar to unittest)
  - simple
  - verbose (default)
  All of these styles are colored to emphasize errors.
  If you want change reporting style, specify ``-r`` option in command-line.

* New assertion method ``ok(x).attr(name, value)`` to check attribute.
  ex::

    d = datetime.date(2000, 12, 31)
    ok (d).attr('year', 2000).attr('month', 12).attr('date', 31)

* New assertion method ``ok(x).length(n)``. This is same as
  ``ok(len(x)) == n``, but it is useful when chaining assertion methods.
  ex::

    ok (func()).is_a(tuple).length(2)

* New feature``ok().should`` helps you to check boolean method.
  ex::

    ## same as ok ("Haruhi".startswith("Haru")) == True
    ok ("Haruhi").should.startswith("Haru")

    ## same as ok ("Haruhi".isupper()) == False
    ok ("Haruhi").should_not.isupper()

* 'ok(str1) == str2' displays diff if text1 != text2, even when using
  with unittest module. In previous version, text diff is displayed
  only when using oktest.run().
  If you are unittest user and using Python < 2.7, use 'ok(str1) == str2'
  instead of 'self.assertEqual(str2, str1)' to display text diff.

* Assertion ``raises()`` supports regular expression to check error message.

    def fn(): raise ValueError("ERROR-123")
    ok (fn).raises(ValueError, re.compile(r'^[A-Z]+-\d+$'))

* Helper functions in oktest.dummy module are now available as decorator.
  This is useful when you must use Python 2.4::

    from oktest.dummy import dummy_io
    ## for Python 2.4
    @dummy_io("SOS")
    def d_io():
        assert sys.stdin.read() == "SOS"
        print("Haruhi")
    sout, serr = d_io
    assert sout == "Haruhi\n"
    ## for Python 2.5 or later
    with dummy_io("SOS") as d_io:
        assert sys.stdin.read() == "SOS"
        print("Haruhi")
    sout, serr = d_io
    assert sout == "Haruhi\n"

* 'AssertionObject.expected' is renamed to 'AssertionObject.boolean'.
  You should update your custom assertion definition.
  ex::

    import oktest
    @oktest.assertion
    def startswith(self, arg):
        boolean = self.target.startswith(arg)
        #if boolean == self.expected:      # obsolete
        if boolean == self.boolean:
            return True
        self.failed("%r.startswith(%r) : failed." % (self.target, arg))

* ``oktest.run()`` is changed to return number of failures and errors
  of tests.::

    sys.exit(oktest.run())   # status code == number of failures and errors

* ``before_each()`` and ``after_each()`` are now non-supported.
  Use ``before()`` and ``after()`` intead.

* (Experimental) New function ``NOT()`` provided which is same as ``NG()``.

* (Experimental) ``skip()`` and ``@skip.when()`` are provided to skip tests::

    from oktest import skip

    class FooTest(unittest.TestCase):

        def test_1(self):
            if sys.version.startswith('2.'):
                reason = "not available on Python 2.x"
                skip(reason)    # raises SkipTest
            ...

        @skip.when(sys.version.startswith('2.'), "not available on Python 2.x")
        def test_2(self):
            ...

  If you want to use @skip.when with @test decorator, see the folloing::

     ## OK
     @test("description")
     @skip.when(condition, "reason")
     def _(self):
         ...

     ## NG
     @skip.when(condition, "reason")
     @test("description")
     def _(self):
         ...


Release 0.8.0
-------------

* add ``NG()`` which is same as not_ok().

* enhanced to proive egg files for Python 3.

* enhanced to support assertion method chaining. ::

    ok ("sos".upper()).is_a(str).matches(r'^[A-Z]+$') == "SOS"

* ``ok().matches()`` can take flag parameter which is passed to re.compile().

    ok ("\nSOS\n").matches(r'^[A-Z]+$', re.M)
    ## same as:
    #ok("\nSOS\n").matches(r.compile(r'^[A-Z]$', re.M))

* enhance helper methods to be available without with-statement.
  (this is necessary for Python 2.4 which is default version on CentOS.)

    from oktest.helper import chdir

    def fn():
      ok (os.getcwd()) == "/tmp"
    chdir("/tmp").run(fn)
    ## this is same as:
    #with chdir("/tmp"):
    #  ok (os.getcwd()) == "/tmp"

    from oktest.dummy import dummy_file

    def fn():
      ok ("A.txt").is_file()
      ok (open("A.txt").read()) == "SOS"
    dummy_file("A.txt", "SOS").run(fun)
    ## this is same as:
    #with dummy_file("A.txt", "SOS"):
    #  ok (open("A.txt").read()) == "SOS"

* ``spec()`` now checks environment variable $SPEC.
  This is useful to filter test cases.

    ## test script
    from oktest import oktest, run
    class StrTest(object):
      def test_upper(self):
        if spec("returns upper case string"):
          ok ("sos".upper()) == "SOS"
        if spec("doesn't change non-alphabetics"):
          ok ("sos123<>".upper()) == "SOS123<>"
    if __name__ == "__main__":
      run()

    ## terminal
    $ SPEC="returns upper case string" python test1.py

* fix ``oktest.run()`` to print correct traceback if ok() is called from
  nested function.

* fix content of README.txt.



Release 0.7.0
-------------

* enhanced to allow users to define custom assertion functions. ::

    import oktest
    from oktest import ok
    #
    @oktest.assertion
    def startswith(self, arg):
        boolean = self.target.startswith(arg)
        if boolean == self.expected:
            return True
        self.failed("%r.startswith(%r) : failed." % (self.target, arg))
    #
    ok ("Sasaki").startswith("Sas")

* rename 'ok().hasattr()' to 'ok().has_attr()'.
  (but old name is also available for backward compatibility.)

* change 'chdir()' to take a function as 2nd argument. ::

    def f():
      ... do_something ...
    chdir('build', f)

    # The above is same as:
    with chdir('build'):
      ... do_something ...

* add document of 'oktest.helper.dummy_io()'. ::

    with dummy_io("SOS") as io:
        assert sys.stdin.read() == "SOS"
        print("Haruhi")
    assert io.stdout == "Haruhi\n"
    assert io.stderr == ""

* fix 'oktest.tracer.Call#__repr__()' to change output according to
  whether '==' is called or not. This is aimed to make output of
  'ok(tr[0]) == [...]' to be more readable.

* change 'Runner#run()' to skip AssertionError if it is raised by
  'assert ....' and not 'ok() == ...'.


Release 0.6.0
-------------

* enhanced to add 'oktest.tracer.Tracer' class. see README for details.
* change 'run()' to sort classes order by lineno in source file.
* change default argument of 'run()' from '.*Test(Case)$' to
  '.*(Test|TestCase|_TC)$'.


Release 0.5.0
-------------

* change default argument of 'run()' to '.*Test(Case)$'.
* enhanced to report untested AssertionObject.
* new helper function 'spec()' which describes test specification.
* new helper function 'dummy_values()' which changes dictionary temporarily.
* new helper function 'dummy_attrs()' which changes object's attributes temporarily.
* 'TestCaseRunner' class is renamed to 'TestRunner'.
* (undocumented) new helper function 'dummy_environ_vars()'.
* (undocumented) new helper function 'using()'.
* (uncodumented) add rm_rf()


Release 0.4.0
-------------

* enhanced to support 'ok (x).in_delta(y, d)' which raises assertion exception
  unless y-d < x < y+d.
* change test script to support Python 2.7 and 3.x.
* fixed several bugs.


Release 0.3.0
-------------

* enhanced 'ok (s1) == s2' to display unified diff (diff -u)
* changed to call 'before()/after()' instead of 'before_each()/after_each()'
  (currently 'before_each()/after_each()' is also enabled but they will be
   disabled in the future)
* improved compatibility with unittest module
* (internal) 'ValueObject' class is renamed to 'AssertionObject'
* (internal) 'Reporter#before_each()' and '#after_each()' are renamed into
  '#before()' and '#after()'


Release 0.2.2
-------------

* enhanced to set 'f.exception' after 'ok (f).raises(Exception)'
  to get raised exception object
* changed to flush output after '.'/'f'/'E' printed
* change to get exception message by 'str(ex)' instead of 'ex.message'


Release 0.2.1
-------------

* fix 'REAMDE.txt'
* fix 'setup.py'


Release 0.2.0
-------------

* public release