Mark scoped_refptr move and swap operations as noexcept

to align with chromium scoped_refptr implementation
and prefer move over copy in some cases.

Bug: webrtc:11078
Change-Id: I3178e74e611e4b23435668878e6bcc98bc2ce77d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159541
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29768}
diff --git a/api/scoped_refptr_unittest.cc b/api/scoped_refptr_unittest.cc
new file mode 100644
index 0000000..75a202b
--- /dev/null
+++ b/api/scoped_refptr_unittest.cc
@@ -0,0 +1,111 @@
+/*
+ *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/scoped_refptr.h"
+
+#include <utility>
+#include <vector>
+
+#include "test/gtest.h"
+
+namespace rtc {
+namespace {
+
+struct FunctionsCalled {
+  int addref = 0;
+  int release = 0;
+};
+
+class ScopedRefCounted {
+ public:
+  explicit ScopedRefCounted(FunctionsCalled* called) : called_(*called) {}
+  ScopedRefCounted(const ScopedRefCounted&) = delete;
+  ScopedRefCounted& operator=(const ScopedRefCounted&) = delete;
+
+  void AddRef() {
+    ++called_.addref;
+    ++ref_count_;
+  }
+  void Release() {
+    ++called_.release;
+    if (0 == --ref_count_)
+      delete this;
+  }
+
+ private:
+  ~ScopedRefCounted() = default;
+
+  FunctionsCalled& called_;
+  int ref_count_ = 0;
+};
+
+TEST(ScopedRefptrTest, IsCopyConstructable) {
+  FunctionsCalled called;
+  scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+  scoped_refptr<ScopedRefCounted> another_ptr = ptr;
+
+  EXPECT_TRUE(ptr);
+  EXPECT_TRUE(another_ptr);
+  EXPECT_EQ(called.addref, 2);
+}
+
+TEST(ScopedRefptrTest, IsCopyAssignable) {
+  FunctionsCalled called;
+  scoped_refptr<ScopedRefCounted> another_ptr;
+  scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+  another_ptr = ptr;
+
+  EXPECT_TRUE(ptr);
+  EXPECT_TRUE(another_ptr);
+  EXPECT_EQ(called.addref, 2);
+}
+
+TEST(ScopedRefptrTest, IsMoveConstructableWithoutExtraAddRefRelease) {
+  FunctionsCalled called;
+  scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+  scoped_refptr<ScopedRefCounted> another_ptr = std::move(ptr);
+
+  EXPECT_FALSE(ptr);
+  EXPECT_TRUE(another_ptr);
+  EXPECT_EQ(called.addref, 1);
+  EXPECT_EQ(called.release, 0);
+}
+
+TEST(ScopedRefptrTest, IsMoveAssignableWithoutExtraAddRefRelease) {
+  FunctionsCalled called;
+  scoped_refptr<ScopedRefCounted> another_ptr;
+  scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+  another_ptr = std::move(ptr);
+
+  EXPECT_FALSE(ptr);
+  EXPECT_TRUE(another_ptr);
+  EXPECT_EQ(called.addref, 1);
+  EXPECT_EQ(called.release, 0);
+}
+
+TEST(ScopedRefptrTest, MovableDuringVectorReallocation) {
+  static_assert(
+      std::is_nothrow_move_constructible<scoped_refptr<ScopedRefCounted>>(),
+      "");
+  // Test below describes a scenario where it is helpful for move constructor
+  // to be noexcept.
+  FunctionsCalled called;
+  std::vector<scoped_refptr<ScopedRefCounted>> ptrs;
+  ptrs.reserve(1);
+  // Insert more elements than reserved to provoke reallocation.
+  ptrs.push_back(new ScopedRefCounted(&called));
+  ptrs.push_back(new ScopedRefCounted(&called));
+
+  EXPECT_EQ(called.addref, 2);
+  EXPECT_EQ(called.release, 0);
+}
+
+}  // namespace
+}  // namespace rtc