You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2018/12/28 09:33:29 UTC

svn commit: r1849831 - in /subversion/trunk/subversion/bindings/cxx: include/svnxx/revision.hpp src/private.hpp src/private/revision-private.hpp src/revision.cpp tests/test_revision.cpp

Author: brane
Date: Fri Dec 28 09:33:29 2018
New Revision: 1849831

URL: http://svn.apache.org/viewvc?rev=1849831&view=rev
Log:
Add SVN++ encapsulation of svn_revnum_t and svn_opt_revision_t.

[in subversion/bindings/cxx]
* include/svnxx/revision.hpp: New.
* src/private/revision-private.hpp: New.
* src/private.hpp: Include revision-private.hpp.
* src/revision.cpp: New.
* tests/test_revision.cpp: New.

Added:
    subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp   (with props)
    subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp   (with props)
    subversion/trunk/subversion/bindings/cxx/src/revision.cpp   (with props)
    subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp   (with props)
Modified:
    subversion/trunk/subversion/bindings/cxx/src/private.hpp

Added: subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp?rev=1849831&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp (added)
+++ subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp Fri Dec 28 09:33:29 2018
@@ -0,0 +1,369 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#ifndef SVNXX_REVISION_HPP
+#define SVNXX_REVISION_HPP
+
+#include <chrono>
+#include <cstdint>
+
+#include "tristate.hpp"
+
+namespace apache {
+namespace subversion {
+namespace svnxx {
+
+/**
+ * @brief A revision, see @ref svn_opt_revision_t.
+ *
+ * The @c revision can represent a revision number, a point in time
+ * in the repository or a property of the working copy or repository
+ * node (see revision::kind).
+ */
+class revision
+{
+public:
+  /**
+   * @brief Revisiion number type.
+   */
+  enum class number : long
+    {
+      invalid = -1,             //< Invalid revision number.
+    };
+
+  /**
+   * @brief Revision by date/time uses the system clock.
+   */
+  template<typename Duration>
+  using time = std::chrono::time_point<std::chrono::system_clock, Duration>;
+
+  /**
+   * @brief The resolution of the stored date/time.
+   */
+  using usec = std::chrono::microseconds;
+
+  /**
+   * @brief Revision kind discriminator (see @ref svn_opt_revision_kind).
+   */
+  // NOTE: Keep these values identical to those in svn_opt_revision_kind!
+  enum class kind : std::int8_t
+    {
+      unspecified,
+      number,
+      date,
+      committed,
+      previous,
+      base,
+      working,
+      head,
+    };
+
+  /**
+   * @brief Default constructor.
+   * @post get_kind() == kind::unspecified.
+   */
+  revision() noexcept
+    : tag(kind::unspecified)
+    {}
+
+  /**
+   * @brief Construct a revision of the given kind.
+   * @pre The @a revkind argument may be any @c kind value @b except
+   *      kind::number or kind::date, which require additional
+   *      parameters and therefore have their own constructors.
+   * @post get_kind() == @a revkind.
+   * @throw std::invalid_argument if the @a revkind value
+   *        precondition is not met.
+   */
+  explicit revision(kind revkind)
+    : tag(revkind)
+    {
+      if (revkind == kind::number || revkind == kind::date)
+        throw std::invalid_argument("invalid svn::revision::kind");
+    }
+
+  /**
+   * @brief Construct a numbered revision.
+   * @post get_kind() == kind::number.
+   */
+  explicit revision(number revnum_) noexcept
+    : tag(kind::number),
+      revnum(revnum_)
+    {}
+
+  /**
+   * @brief Construct a dated revision from a system clock time point.
+   * @post get_kind() == kind::date.
+   */
+  template<typename D>
+  explicit revision(time<D> time_) noexcept
+    : tag(kind::date),
+      date(std::chrono::time_point_cast<usec>(time_))
+    {}
+
+  /**
+   * @brief Return the revision kind.
+   */
+  kind get_kind() const noexcept
+    {
+      return tag;
+    }
+
+  /**
+   * @brief Return the revision number.
+   * @pre get_kind() == kind::number.
+   * @throw std::logic_error if the precondition is not met.
+   */
+  number get_number() const
+    {
+      if (tag != kind::number)
+        throw std::logic_error("svn::revision kind != number");
+      return revnum;
+    }
+
+  /**
+   * @brief Return the revision date/time as a system clock time point.
+   * @pre get_kind() == kind::date.
+   * @throw std::logic_error if the precondition is not met.
+   */
+  template<typename D>
+  time<D> get_date() const
+    {
+      if (tag != kind::date)
+        throw std::logic_error("svn::revision kind != date");
+      return std::chrono::time_point_cast<D>(date);
+    }
+
+private:
+  // Even if we were using C++17, we wouldn't use std::variant because we
+  // already maintain an explicit discriminator tag for the union.
+  kind tag;           // Union discriminator
+  union {
+    number revnum;    // (tag == kind::number): revision number.
+    time<usec> date;  // (tag == kind::date): microseconds from epoch.
+  };
+};
+
+/**
+ * @related revision
+ * @brief revision::number alias for convenience.
+ */
+using revnum = revision::number;
+
+/**
+ * @related revision
+ * @brief Equality comparison.
+ */
+inline bool operator==(const revision& a, const revision& b)
+{
+  const auto kind = a.get_kind();
+  if (kind != b.get_kind())
+    return false;
+  else if (kind == revision::kind::number)
+    return a.get_number() == b.get_number();
+  else if (kind == revision::kind::date)
+    return a.get_date<revision::usec>() == b.get_date<revision::usec>();
+  else
+    return true;
+}
+
+/**
+ * @related revision
+ * @brief Inequality comparison.
+ */
+inline bool operator!=(const revision& a, const revision& b)
+{
+  return !(a == b);
+}
+
+/**
+ * @related revision
+ * @brief Ordering: less-than (<tt>operator @<</tt>).
+ * @returns a @c tristate result of comparing two @c revision values,
+ * according to the following table:
+ *   <table border=1>
+ *     <tr>
+ *       <th><center><code>@<</code></center></th>
+ *       <th><center><tt>number</tt></center></th>
+ *       <th><center><tt>date</tt></center></th>
+ *       <th><center><em>other</em></center></th>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>number</tt></center></th>
+ *       <td><center><tt>a.get_number() < b.get_number()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>date</tt></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><tt>a.get_date() < b.get_date()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><em>other</em></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *   </table>
+ */
+inline tristate operator<(const revision& a, const revision& b)
+{
+  const auto kind = a.get_kind();
+  if (kind != b.get_kind())
+    return tristate::unknown();
+  else if (kind == revision::kind::number)
+    return a.get_number() < b.get_number();
+  else if (kind == revision::kind::date)
+    return a.get_date<revision::usec>() < b.get_date<revision::usec>();
+  else
+    return tristate::unknown();
+}
+
+/**
+ * @related revision
+ * @brief Ordering: greater-than (<tt>operator @></tt>).
+ * @returns a @c tristate result of comparing two @c revision values,
+ * according to the following table:
+ *   <table border=1>
+ *     <tr>
+ *       <th><center><code>@></code></center></th>
+ *       <th><center><tt>number</tt></center></th>
+ *       <th><center><tt>date</tt></center></th>
+ *       <th><center><em>other</em></center></th>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>number</tt></center></th>
+ *       <td><center><tt>a.get_number() > b.get_number()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>date</tt></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><tt>a.get_date() > b.get_date()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><em>other</em></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *   </table>
+ */
+inline tristate operator>(const revision& a, const revision& b)
+{
+  const auto kind = a.get_kind();
+  if (kind != b.get_kind())
+    return tristate::unknown();
+  else if (kind == revision::kind::number)
+    return a.get_number() > b.get_number();
+  else if (kind == revision::kind::date)
+    return a.get_date<revision::usec>() > b.get_date<revision::usec>();
+  else
+    return tristate::unknown();
+}
+
+/**
+ * @related revision
+ * @brief Ordering: less-or-equal (<tt>operator @<=</tt>).
+ * @returns a @c tristate result of comparing two @c revision values,
+ * according to the following table:
+ *   <table border=1>
+ *     <tr>
+ *       <th><center><code>@<=</code></center></th>
+ *       <th><center><tt>number</tt></center></th>
+ *       <th><center><tt>date</tt></center></th>
+ *       <th><center><em>other</em></center></th>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>number</tt></center></th>
+ *       <td><center><tt>a.get_number() <= b.get_number()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>date</tt></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><tt>a.get_date() <= b.get_date()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><em>other</em></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
+ *     </tr>
+ *   </table>
+ * &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
+ */
+inline tristate operator<=(const revision& a, const revision& b)
+{
+  return (a == b || !(a > b));
+}
+
+/**
+ * @related revision
+ * @brief Ordering: greater-or-equal (<tt>operator @>=</tt>).
+ * @returns a @c tristate result of comparing two @c revision values,
+ * according to the following table:
+ *   <table border=1>
+ *     <tr>
+ *       <th><center><code>@>=</code></center></th>
+ *       <th><center><tt>number</tt></center></th>
+ *       <th><center><tt>date</tt></center></th>
+ *       <th><center><em>other</em></center></th>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>number</tt></center></th>
+ *       <td><center><tt>a.get_number() >= b.get_number()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><tt>date</tt></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><tt>a.get_date() >= b.get_date()</tt></td>
+ *       <td><center><em>unknown</em></center></td>
+ *     </tr>
+ *     <tr>
+ *       <th><center><em>other</em></center></th>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>unknown</em></center></td>
+ *       <td><center><em>true</em>&dagger; or <em>unknown</em></center></td>
+ *     </tr>
+ *   </table>
+ * &dagger; <em>true</em> when <tt>a.get_kind() == b.get_kind()</tt>.
+ */
+inline tristate operator>=(const revision& a, const revision& b)
+{
+  return (a == b || !(a < b));
+}
+
+} // namespace svnxx
+} // namespace subversion
+} // namespace apache
+
+#endif  // SVNXX_REVISION_HPP

Propchange: subversion/trunk/subversion/bindings/cxx/include/svnxx/revision.hpp
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/trunk/subversion/bindings/cxx/src/private.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/private.hpp?rev=1849831&r1=1849830&r2=1849831&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/private.hpp (original)
+++ subversion/trunk/subversion/bindings/cxx/src/private.hpp Fri Dec 28 09:33:29 2018
@@ -26,6 +26,7 @@
 
 #include "private/depth-private.hpp"
 #include "private/exception-private.hpp"
+#include "private/revision-private.hpp"
 #include "private/strings-private.hpp"
 #include "private/tristate-private.hpp"
 

Added: subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp?rev=1849831&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp (added)
+++ subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp Fri Dec 28 09:33:29 2018
@@ -0,0 +1,62 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#ifndef SVNXX_PRIVATE_REVISION_HPP
+#define SVNXX_PRIVATE_REVISION_HPP
+
+#include "svnxx/revision.hpp"
+
+#include "svn_types.h"
+#include "svn_opt.h"
+
+namespace apache {
+namespace subversion {
+namespace svnxx {
+namespace detail {
+
+/**
+ * Convert @a kind to an svn_opt_revision_kind.
+ */
+svn_opt_revision_kind convert(revision::kind kind);
+
+/**
+ * Convert @a kind to an svn::revision::kind.
+ */
+revision::kind convert(svn_opt_revision_kind kind);
+
+/**
+ * Convert @a rev to an svn_opt_revision_t.
+ */
+svn_opt_revision_t convert(const revision& rev);
+
+/**
+ * Convert @a rev to an svn::revision.
+ */
+revision convert(const svn_opt_revision_t& rev);
+
+} // namespace detail
+} // namespace svnxx
+} // namespace subversion
+} // namespace apache
+
+#endif // SVNXX_PRIVATE_REVISION_HPP

Propchange: subversion/trunk/subversion/bindings/cxx/src/private/revision-private.hpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/cxx/src/revision.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/src/revision.cpp?rev=1849831&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/src/revision.cpp (added)
+++ subversion/trunk/subversion/bindings/cxx/src/revision.cpp Fri Dec 28 09:33:29 2018
@@ -0,0 +1,165 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include <stdexcept>
+
+#include "private/revision-private.hpp"
+
+namespace apache {
+namespace subversion {
+namespace svnxx {
+namespace detail {
+
+svn_opt_revision_kind convert(revision::kind kind)
+{
+#ifdef SVN_DEBUG
+  switch (kind)
+    {
+    case revision::kind::unspecified:
+      if (kind != svn_opt_revision_unspecified)
+        throw std::range_error("convert svn::revision::kind::unspecified");
+      break;
+
+    case revision::kind::number:
+      if (kind != svn_opt_revision_number)
+        throw std::range_error("convert svn::revision::kind::number");
+      break;
+
+    case revision::kind::date:
+      if (kind != svn_opt_revision_date)
+        throw std::range_error("convert svn::revision::kind::date");
+      break;
+
+    case revision::kind::committed:
+      if (kind != svn_opt_revision_committed)
+        throw std::range_error("convert svn::revision::kind::committed");
+      break;
+
+    case revision::kind::base:
+      if (kind != svn_opt_revision_base)
+        throw std::range_error("convert svn::revision::kind::base");
+      break;
+
+    case revision::kind::working:
+      if (kind != svn_opt_revision_working)
+        throw std::range_error("convert svn::revision::kind::working");
+      break;
+
+    case revision::kind::head:
+      if (kind != svn_opt_revision_head)
+        throw std::range_error("convert svn::revision::kind::head");
+      break;
+
+    default:
+      throw std::range_error("unknown svn::revision::kind");
+    }
+#endif
+  return svn_opt_revision_kind(kind);
+}
+
+revision::kind convert(svn_opt_revision_kind kind)
+{
+#ifdef SVN_DEBUG
+  switch (kind)
+    {
+    case svn_opt_revision_unspecified:
+      if (kind != revision::kind::unspecified)
+        throw std::range_error("convert svn_opt_revision_unspecified");
+      break;
+
+    case svn_opt_revision_number:
+      if (kind != revision::kind::number)
+        throw std::range_error("convert svn_opt_revision_number");
+      break;
+
+    case svn_opt_revision_date:
+      if (kind != revision::kind::date)
+        throw std::range_error("convert svn_opt_revision_date");
+      break;
+
+    case svn_opt_revision_committed:
+      if (kind != revision::kind::committed)
+        throw std::range_error("convert svn_opt_revision_committed");
+      break;
+
+    case svn_opt_revision_base:
+      if (kind != revision::kind::base)
+        throw std::range_error("convert svn_opt_revision_base");
+      break;
+
+    case svn_opt_revision_working:
+      if (kind != revision::kind::working)
+        throw std::range_error("convert svn_opt_revision_working");
+      break;
+
+    case svn_opt_revision_head:
+      if (kind != revision::kind::head)
+        throw std::range_error("convert svn_opt_revision_head");
+      break;
+
+    default:
+      throw std::range_error("unknown svn_opt_revision_kind");
+    }
+#endif
+  return revision::kind(kind);
+}
+
+svn_opt_revision_t convert(const revision& rev)
+{
+  svn_opt_revision_t result;
+  result.kind = convert(rev.get_kind());
+  if (result.kind == svn_opt_revision_number)
+    result.value.number = svn_revnum_t(rev.get_number());
+  else if (result.kind == svn_opt_revision_date)
+    {
+      // NOTE: We're assuming that the APR and C++ system_clock epochs
+      //       are the same. This will be standardized in C++20.
+      using usec = revision::usec;
+      const auto usecs = (rev.get_date<usec>() - revision::time<usec>());
+      result.value.date = usecs.count();
+    }
+  return result;
+}
+
+revision convert(const svn_opt_revision_t& rev)
+{
+  switch (rev.kind)
+    {
+    case svn_opt_revision_number:
+      return revision(revision::number(rev.value.number));
+    case svn_opt_revision_date:
+      {
+        // NOTE: We're assuming that the APR and C++ system_clock epochs
+        //       are the same. This will be standardized in C++20.
+        using usec = revision::usec;
+        return revision(revision::time<usec>(usec{rev.value.date}));
+      }
+    default:
+      return revision(convert(rev.kind));
+    }
+}
+
+} // namespace detail
+} // namespace svnxx
+} // namespace subversion
+} // namespace apache

Propchange: subversion/trunk/subversion/bindings/cxx/src/revision.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp?rev=1849831&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp (added)
+++ subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp Fri Dec 28 09:33:29 2018
@@ -0,0 +1,137 @@
+/*
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include <array>
+
+#include "../src/private/revision-private.hpp"
+
+namespace svn = ::apache::subversion::svnxx;
+namespace detail = ::apache::subversion::svnxx::detail;
+
+BOOST_AUTO_TEST_SUITE(revision);
+
+BOOST_AUTO_TEST_CASE(convert_to_kind)
+{
+  using kind = svn::revision::kind;
+  BOOST_TEST((detail::convert(kind::unspecified) == svn_opt_revision_unspecified));
+  BOOST_TEST((detail::convert(kind::number)      == svn_opt_revision_number));
+  BOOST_TEST((detail::convert(kind::date)        == svn_opt_revision_date));
+  BOOST_TEST((detail::convert(kind::committed)   == svn_opt_revision_committed));
+  BOOST_TEST((detail::convert(kind::previous)    == svn_opt_revision_previous));
+  BOOST_TEST((detail::convert(kind::base)        == svn_opt_revision_base));
+  BOOST_TEST((detail::convert(kind::working)     == svn_opt_revision_working));
+  BOOST_TEST((detail::convert(kind::head)        == svn_opt_revision_head));
+}
+
+BOOST_AUTO_TEST_CASE(convert_from_kind)
+{
+  using kind = svn::revision::kind;
+  BOOST_TEST((detail::convert(svn_opt_revision_unspecified) == kind::unspecified));
+  BOOST_TEST((detail::convert(svn_opt_revision_number)      == kind::number));
+  BOOST_TEST((detail::convert(svn_opt_revision_date)        == kind::date));
+  BOOST_TEST((detail::convert(svn_opt_revision_committed)   == kind::committed));
+  BOOST_TEST((detail::convert(svn_opt_revision_previous)    == kind::previous));
+  BOOST_TEST((detail::convert(svn_opt_revision_base)        == kind::base));
+  BOOST_TEST((detail::convert(svn_opt_revision_working)     == kind::working));
+  BOOST_TEST((detail::convert(svn_opt_revision_head)        == kind::head));
+}
+
+BOOST_AUTO_TEST_CASE(roundtrip_conversions)
+{
+  using kind = svn::revision::kind;
+  using usec = svn::revision::usec;
+
+  std::array<svn::revision, 11> data = {
+    svn::revision(),
+    svn::revision(kind::unspecified),
+    svn::revision(kind::committed),
+    svn::revision(kind::previous),
+    svn::revision(kind::base),
+    svn::revision(kind::working),
+    svn::revision(kind::head),
+    svn::revision(svn::revnum::invalid),
+    svn::revision(svn::revnum(7)),
+    svn::revision(svn::revision::time<usec>()),
+    svn::revision(svn::revision::time<usec>(usec{11})),
+  };
+
+  for (const auto& r : data)
+    BOOST_TEST((detail::convert(detail::convert(r)) == r));
+}
+
+BOOST_AUTO_TEST_CASE(preconditions)
+{
+  using kind = svn::revision::kind;
+  BOOST_CHECK_THROW(auto r = svn::revision(kind::number), std::invalid_argument);
+  BOOST_CHECK_THROW(auto r = svn::revision(kind::date), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(postconditions_kind)
+{
+  using kind = svn::revision::kind;
+  using usec = svn::revision::usec;
+
+  BOOST_TEST((svn::revision(kind::unspecified).get_kind() == kind::unspecified));
+  BOOST_TEST((svn::revision(kind::committed)  .get_kind() == kind::committed));
+  BOOST_TEST((svn::revision(kind::previous)   .get_kind() == kind::previous));
+  BOOST_TEST((svn::revision(kind::base)       .get_kind() == kind::base));
+  BOOST_TEST((svn::revision(kind::working)    .get_kind() == kind::working));
+  BOOST_TEST((svn::revision(kind::head)       .get_kind() == kind::head));
+}
+
+BOOST_AUTO_TEST_CASE(postconditions_default)
+{
+  using kind = svn::revision::kind;
+  using usec = svn::revision::usec;
+
+  const auto r = svn::revision();
+  BOOST_TEST((r.get_kind() == kind::unspecified));
+  BOOST_CHECK_THROW(r.get_number(), std::logic_error);
+  BOOST_CHECK_THROW(r.get_date<usec>(), std::logic_error);
+}
+
+BOOST_AUTO_TEST_CASE(postconditions_number)
+{
+  using kind = svn::revision::kind;
+  using usec = svn::revision::usec;
+
+  const auto r = svn::revision(svn::revnum::invalid);
+  BOOST_TEST((r.get_kind() == kind::number));
+  BOOST_TEST((r.get_number() == svn::revnum::invalid));
+  BOOST_CHECK_THROW(r.get_date<usec>(), std::logic_error);
+}
+
+BOOST_AUTO_TEST_CASE(postconditions_date)
+{
+  using kind = svn::revision::kind;
+  using usec = svn::revision::usec;
+
+  const auto r = svn::revision(svn::revision::time<usec>());
+  BOOST_TEST((r.get_kind() == kind::date));
+  BOOST_TEST((r.get_date<usec>() == svn::revision::time<usec>()));
+  BOOST_CHECK_THROW(r.get_number(), std::logic_error);
+}
+
+// TODO: Add tests for !=, <, >, <= and >=
+
+BOOST_AUTO_TEST_SUITE_END();

Propchange: subversion/trunk/subversion/bindings/cxx/tests/test_revision.cpp
------------------------------------------------------------------------------
    svn:eol-style = native