1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include <google/protobuf/stubs/common.h>
32 #include <google/protobuf/test_util.h>
33 #include <google/protobuf/unittest.pb.h>
34 #include <gtest/gtest.h>
35
36 #if LANG_CXX11
37 #include <type_traits>
38 #endif
39
40 namespace google {
41 namespace protobuf {
42 namespace compiler {
43 namespace cpp {
44
45 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
46 namespace cpp_unittest {
47
48 // Moves are enabled only when compiling with a C++11 compiler or newer.
49 #if LANG_CXX11
50
TEST(MovableMessageTest,MoveConstructor)51 TEST(MovableMessageTest, MoveConstructor) {
52 protobuf_unittest::TestAllTypes message1;
53 TestUtil::SetAllFields(&message1);
54 const auto* nested = &message1.optional_nested_message();
55
56 protobuf_unittest::TestAllTypes message2(std::move(message1));
57 TestUtil::ExpectAllFieldsSet(message2);
58
59 // Check if the optional_nested_message was actually moved (and not just
60 // copied).
61 EXPECT_EQ(nested, &message2.optional_nested_message());
62 EXPECT_NE(nested, &message1.optional_nested_message());
63 }
64
TEST(MovableMessageTest,MoveAssignmentOperator)65 TEST(MovableMessageTest, MoveAssignmentOperator) {
66 protobuf_unittest::TestAllTypes message1;
67 TestUtil::SetAllFields(&message1);
68 const auto* nested = &message1.optional_nested_message();
69
70 protobuf_unittest::TestAllTypes message2;
71 message2 = std::move(message1);
72 TestUtil::ExpectAllFieldsSet(message2);
73
74 // Check if the optional_nested_message was actually moved (and not just
75 // copied).
76 EXPECT_EQ(nested, &message2.optional_nested_message());
77 EXPECT_NE(nested, &message1.optional_nested_message());
78 }
79
TEST(MovableMessageTest,SelfMoveAssignment)80 TEST(MovableMessageTest, SelfMoveAssignment) {
81 // The `self` reference is necessary to defeat -Wself-move.
82 protobuf_unittest::TestAllTypes message, &self = message;
83 TestUtil::SetAllFields(&message);
84 message = std::move(self);
85 TestUtil::ExpectAllFieldsSet(message);
86 }
87
TEST(MovableMessageTest,MoveSameArena)88 TEST(MovableMessageTest, MoveSameArena) {
89 Arena arena;
90
91 auto* message1_on_arena =
92 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
93 TestUtil::SetAllFields(message1_on_arena);
94 const auto* nested = &message1_on_arena->optional_nested_message();
95
96 auto* message2_on_arena =
97 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
98
99 // Moving messages on the same arena should lead to swapped pointers.
100 *message2_on_arena = std::move(*message1_on_arena);
101 EXPECT_EQ(nested, &message2_on_arena->optional_nested_message());
102 }
103
TEST(MovableMessageTest,MoveDifferentArenas)104 TEST(MovableMessageTest, MoveDifferentArenas) {
105 Arena arena1, arena2;
106
107 auto* message1_on_arena =
108 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1);
109 TestUtil::SetAllFields(message1_on_arena);
110 const auto* nested = &message1_on_arena->optional_nested_message();
111
112 auto* message2_on_arena =
113 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2);
114
115 // Moving messages on two different arenas should lead to a copy.
116 *message2_on_arena = std::move(*message1_on_arena);
117 EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
118 TestUtil::ExpectAllFieldsSet(*message1_on_arena);
119 TestUtil::ExpectAllFieldsSet(*message2_on_arena);
120 }
121
TEST(MovableMessageTest,MoveFromArena)122 TEST(MovableMessageTest, MoveFromArena) {
123 Arena arena;
124
125 auto* message1_on_arena =
126 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
127 TestUtil::SetAllFields(message1_on_arena);
128 const auto* nested = &message1_on_arena->optional_nested_message();
129
130 protobuf_unittest::TestAllTypes message2;
131
132 // Moving from a message on the arena should lead to a copy.
133 message2 = std::move(*message1_on_arena);
134 EXPECT_NE(nested, &message2.optional_nested_message());
135 TestUtil::ExpectAllFieldsSet(*message1_on_arena);
136 TestUtil::ExpectAllFieldsSet(message2);
137 }
138
TEST(MovableMessageTest,MoveToArena)139 TEST(MovableMessageTest, MoveToArena) {
140 Arena arena;
141
142 protobuf_unittest::TestAllTypes message1;
143 TestUtil::SetAllFields(&message1);
144 const auto* nested = &message1.optional_nested_message();
145
146 auto* message2_on_arena =
147 Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
148
149 // Moving to a message on the arena should lead to a copy.
150 *message2_on_arena = std::move(message1);
151 EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
152 TestUtil::ExpectAllFieldsSet(message1);
153 TestUtil::ExpectAllFieldsSet(*message2_on_arena);
154 }
155
TEST(MovableMessageTest,Noexcept)156 TEST(MovableMessageTest, Noexcept) {
157 EXPECT_TRUE(
158 std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>());
159 EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>());
160 }
161
162 #endif // LANG_CXX11
163
164 } // namespace cpp_unittest
165
166 } // namespace cpp
167 } // namespace compiler
168 } // namespace protobuf
169 } // namespace google
170