From d35d19584cf56a50b4833ff9c003597e01022f27 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Tue, 18 Apr 2017 21:39:24 +0100
Subject: gdb::optional unit tests

I thought I'd add some unit tests to make sure gdb::optional behaved
correctly, and started writing some, but then thought/realized that
libstdc++ already has extensive testing for C++17 std::optional, which
gdb::optional is a subset of, and thought why bother writing something
from scratch.  So I tried copying over a subset of libstdc++'s tests
(that ones that cover the subset supported by gdb::optional), and was
positively surprised that they mostly work OOTB.  This did help shake
out a few bugs from what I was implementing in the previous patch to
gdb::optional.  Still, it's a good chunk of code being copied over, so
if people dislike this copying/duplication, I can drop this patch.

gdb/ChangeLog:
2017-04-18  Pedro Alves  <palves@redhat.com>

	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
	unittests/optional-selftests.c.
	(SUBDIR_UNITTESTS_OBS): Add optional-selftests.o.
	* unittests/optional-selftests.c: New file.
	* unittests/optional/assignment/1.cc: New file.
	* unittests/optional/assignment/2.cc: New file.
	* unittests/optional/assignment/3.cc: New file.
	* unittests/optional/assignment/4.cc: New file.
	* unittests/optional/assignment/5.cc: New file.
	* unittests/optional/assignment/6.cc: New file.
	* unittests/optional/assignment/7.cc: New file.
	* unittests/optional/cons/copy.cc: New file.
	* unittests/optional/cons/default.cc: New file.
	* unittests/optional/cons/move.cc: New file.
	* unittests/optional/cons/value.cc: New file.
	* unittests/optional/in_place.cc: New file.
	* unittests/optional/observers/1.cc: New file.
	* unittests/optional/observers/2.cc: New file.
---
 gdb/unittests/optional/assignment/3.cc | 156 +++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 gdb/unittests/optional/assignment/3.cc

(limited to 'gdb/unittests/optional/assignment/3.cc')

diff --git a/gdb/unittests/optional/assignment/3.cc b/gdb/unittests/optional/assignment/3.cc
new file mode 100644
index 0000000..e047e74
--- /dev/null
+++ b/gdb/unittests/optional/assignment/3.cc
@@ -0,0 +1,156 @@
+// Copyright (C) 2013-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+namespace assign_3 {
+
+struct exception {};
+
+int counter = 0;
+
+struct mixin_counter
+{
+  mixin_counter() { ++counter; }
+  mixin_counter(mixin_counter const&) { ++counter; }
+  ~mixin_counter() { --counter; }
+};
+
+struct value_type : private mixin_counter
+{
+  enum state_type
+  {
+    zero,
+    moved_from,
+    throwing_construction,
+    throwing_copy,
+    throwing_copy_assignment,
+    throwing_move,
+    throwing_move_assignment,
+    threw,
+  };
+
+  value_type() = default;
+
+  explicit value_type(state_type state_)
+  : state(state_)
+  {
+    throw_if(throwing_construction);
+  }
+
+  value_type(value_type const& other)
+  : state(other.state)
+  {
+    throw_if(throwing_copy);
+  }
+
+  value_type&
+  operator=(value_type const& other)
+  {
+    state = other.state;
+    throw_if(throwing_copy_assignment);
+    return *this;
+  }
+
+  value_type(value_type&& other)
+  : state(other.state)
+  {
+    other.state = moved_from;
+    throw_if(throwing_move);
+  }
+
+  value_type&
+  operator=(value_type&& other)
+  {
+    state = other.state;
+    other.state = moved_from;
+    throw_if(throwing_move_assignment);
+    return *this;
+  }
+
+  void throw_if(state_type match)
+  {
+    if(state == match)
+    {
+      state = threw;
+      throw exception {};
+    }
+  }
+
+  state_type state = zero;
+};
+
+void test()
+{
+  using O = gdb::optional<value_type>;
+  using S = value_type::state_type;
+  auto const make = [](S s = S::zero) { return value_type { s }; };
+
+  enum outcome_type { nothrow, caught, bad_catch };
+
+  // Check value assignment for disengaged optional
+
+  {
+    O o;
+    value_type v = make(S::throwing_copy_assignment);
+    o = v;
+    VERIFY( o && o->state == S::throwing_copy_assignment );
+  }
+
+  {
+    O o;
+    value_type v = make(S::throwing_move_assignment);
+    o = std::move(v);
+    VERIFY( o && o->state == S::throwing_move_assignment );
+  }
+
+  {
+    ATTRIBUTE_UNUSED outcome_type outcome {};
+    O o;
+    value_type v = make(S::throwing_copy);
+
+    try
+    {
+      o = v;
+    }
+    catch(exception const&)
+    { outcome = caught; }
+    catch(...)
+    { outcome = bad_catch; }
+
+    VERIFY( !o );
+  }
+
+  {
+    ATTRIBUTE_UNUSED outcome_type outcome {};
+    O o;
+    value_type v = make(S::throwing_move);
+
+    try
+    {
+      o = std::move(v);
+    }
+    catch(exception const&)
+    { outcome = caught; }
+    catch(...)
+    { outcome = bad_catch; }
+
+    VERIFY( !o );
+  }
+
+  VERIFY( counter == 0 );
+}
+
+} // namespace assign_3
-- 
cgit v1.1