1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "nsASCIIMask.h"
10 #include "nsString.h"
11 #include "nsStringBuffer.h"
12 #include "nsReadableUtils.h"
13 #include "nsCRTGlue.h"
14 #include "mozilla/RefPtr.h"
15 #include "mozilla/Unused.h"
16 #include "gtest/gtest.h"
17 
18 namespace TestMoveString {
19 
20 #define NEW_VAL "**new value**"
21 #define OLD_VAL "old value"
22 
23 typedef mozilla::detail::StringDataFlags Df;
24 
SetAsOwned(nsACString & aStr,const char * aValue)25 static void SetAsOwned(nsACString& aStr, const char* aValue) {
26   size_t len = strlen(aValue);
27   char* data = new char[len + 1];
28   memcpy(data, aValue, len + 1);
29   aStr.Adopt(data, len);
30   EXPECT_EQ(aStr.GetDataFlags(), Df::OWNED | Df::TERMINATED);
31   EXPECT_STREQ(aStr.BeginReading(), aValue);
32 }
33 
ExpectTruncated(const nsACString & aStr)34 static void ExpectTruncated(const nsACString& aStr) {
35   EXPECT_EQ(aStr.Length(), uint32_t(0));
36   EXPECT_STREQ(aStr.BeginReading(), "");
37   EXPECT_EQ(aStr.GetDataFlags(), Df::TERMINATED);
38 }
39 
ExpectNew(const nsACString & aStr)40 static void ExpectNew(const nsACString& aStr) {
41   EXPECT_EQ(aStr.Length(), strlen(NEW_VAL));
42   EXPECT_TRUE(aStr.EqualsASCII(NEW_VAL));
43 }
44 
TEST(MoveString,SharedIntoOwned)45 TEST(MoveString, SharedIntoOwned)
46 {
47   nsCString out;
48   SetAsOwned(out, OLD_VAL);
49   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
50 
51   nsCString in;
52   in.Assign(NEW_VAL);
53   EXPECT_EQ(in.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
54   const char* data = in.get();
55 
56   out.Assign(std::move(in));
57   ExpectTruncated(in);
58   ExpectNew(out);
59 
60   EXPECT_EQ(out.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
61   EXPECT_EQ(out.get(), data);
62 }
63 
TEST(MoveString,OwnedIntoOwned)64 TEST(MoveString, OwnedIntoOwned)
65 {
66   nsCString out;
67   SetAsOwned(out, OLD_VAL);
68   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
69 
70   nsCString in;
71   SetAsOwned(in, NEW_VAL);
72   EXPECT_EQ(in.GetDataFlags(), Df::OWNED | Df::TERMINATED);
73   const char* data = in.get();
74 
75   out.Assign(std::move(in));
76   ExpectTruncated(in);
77   ExpectNew(out);
78 
79   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
80   EXPECT_EQ(out.get(), data);
81 }
82 
TEST(MoveString,LiteralIntoOwned)83 TEST(MoveString, LiteralIntoOwned)
84 {
85   nsCString out;
86   SetAsOwned(out, OLD_VAL);
87   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
88 
89   nsCString in;
90   in.AssignLiteral(NEW_VAL);
91   EXPECT_EQ(in.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
92   const char* data = in.get();
93 
94   out.Assign(std::move(in));
95   ExpectTruncated(in);
96   ExpectNew(out);
97 
98   EXPECT_EQ(out.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
99   EXPECT_EQ(out.get(), data);
100 }
101 
TEST(MoveString,AutoIntoOwned)102 TEST(MoveString, AutoIntoOwned)
103 {
104   nsCString out;
105   SetAsOwned(out, OLD_VAL);
106   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
107 
108   nsAutoCString in;
109   in.Assign(NEW_VAL);
110   EXPECT_EQ(in.GetDataFlags(), Df::INLINE | Df::TERMINATED);
111   const char* data = in.get();
112 
113   out.Assign(std::move(in));
114   ExpectTruncated(in);
115   ExpectNew(out);
116 
117   EXPECT_EQ(out.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
118   EXPECT_NE(out.get(), data);
119 }
120 
TEST(MoveString,DepIntoOwned)121 TEST(MoveString, DepIntoOwned)
122 {
123   nsCString out;
124   SetAsOwned(out, OLD_VAL);
125   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
126 
127   nsDependentCSubstring in(NEW_VAL "garbage after", strlen(NEW_VAL));
128   EXPECT_EQ(in.GetDataFlags(), Df(0));
129 
130   out.Assign(std::move(in));
131   ExpectTruncated(in);
132   ExpectNew(out);
133 
134   EXPECT_EQ(out.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
135 }
136 
TEST(MoveString,VoidIntoOwned)137 TEST(MoveString, VoidIntoOwned)
138 {
139   nsCString out;
140   SetAsOwned(out, OLD_VAL);
141   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
142 
143   nsCString in = VoidCString();
144   EXPECT_EQ(in.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
145 
146   out.Assign(std::move(in));
147   ExpectTruncated(in);
148 
149   EXPECT_EQ(out.Length(), 0u);
150   EXPECT_STREQ(out.get(), "");
151   EXPECT_EQ(out.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
152 }
153 
TEST(MoveString,SharedIntoAuto)154 TEST(MoveString, SharedIntoAuto)
155 {
156   nsAutoCString out;
157   out.Assign(OLD_VAL);
158   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
159 
160   nsCString in;
161   in.Assign(NEW_VAL);
162   EXPECT_EQ(in.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
163   const char* data = in.get();
164 
165   out.Assign(std::move(in));
166   ExpectTruncated(in);
167   ExpectNew(out);
168 
169   EXPECT_EQ(out.GetDataFlags(), Df::REFCOUNTED | Df::TERMINATED);
170   EXPECT_EQ(out.get(), data);
171 }
172 
TEST(MoveString,OwnedIntoAuto)173 TEST(MoveString, OwnedIntoAuto)
174 {
175   nsAutoCString out;
176   out.Assign(OLD_VAL);
177   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
178 
179   nsCString in;
180   SetAsOwned(in, NEW_VAL);
181   EXPECT_EQ(in.GetDataFlags(), Df::OWNED | Df::TERMINATED);
182   const char* data = in.get();
183 
184   out.Assign(std::move(in));
185   ExpectTruncated(in);
186   ExpectNew(out);
187 
188   EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
189   EXPECT_EQ(out.get(), data);
190 }
191 
TEST(MoveString,LiteralIntoAuto)192 TEST(MoveString, LiteralIntoAuto)
193 {
194   nsAutoCString out;
195   out.Assign(OLD_VAL);
196   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
197 
198   nsCString in;
199   in.AssignLiteral(NEW_VAL);
200   EXPECT_EQ(in.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
201   const char* data = in.get();
202 
203   out.Assign(std::move(in));
204   ExpectTruncated(in);
205   ExpectNew(out);
206 
207   EXPECT_EQ(out.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
208   EXPECT_EQ(out.get(), data);
209 }
210 
TEST(MoveString,AutoIntoAuto)211 TEST(MoveString, AutoIntoAuto)
212 {
213   nsAutoCString out;
214   out.Assign(OLD_VAL);
215   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
216 
217   nsAutoCString in;
218   in.Assign(NEW_VAL);
219   EXPECT_EQ(in.GetDataFlags(), Df::INLINE | Df::TERMINATED);
220   const char* data = in.get();
221 
222   out.Assign(std::move(in));
223   ExpectTruncated(in);
224   ExpectNew(out);
225 
226   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
227   EXPECT_NE(out.get(), data);
228 }
229 
TEST(MoveString,DepIntoAuto)230 TEST(MoveString, DepIntoAuto)
231 {
232   nsAutoCString out;
233   out.Assign(OLD_VAL);
234   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
235 
236   nsDependentCSubstring in(NEW_VAL "garbage after", strlen(NEW_VAL));
237   EXPECT_EQ(in.GetDataFlags(), Df(0));
238 
239   out.Assign(std::move(in));
240   ExpectTruncated(in);
241   ExpectNew(out);
242 
243   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
244 }
245 
TEST(MoveString,VoidIntoAuto)246 TEST(MoveString, VoidIntoAuto)
247 {
248   nsAutoCString out;
249   out.Assign(OLD_VAL);
250   EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
251 
252   nsCString in = VoidCString();
253   EXPECT_EQ(in.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
254 
255   out.Assign(std::move(in));
256   ExpectTruncated(in);
257 
258   EXPECT_EQ(out.Length(), 0u);
259   EXPECT_STREQ(out.get(), "");
260   EXPECT_EQ(out.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
261 }
262 
263 #undef NEW_VAL
264 #undef OLD_VAL
265 
266 }  // namespace TestMoveString
267