1+ #include < tst/check.hpp>
2+ #include < tst/set.hpp>
3+ #include < utki/unique_ref.hpp>
4+
5+ namespace {
6+ const std::string etalon = " hello world!" ;
7+
8+ struct a0 {
9+ int a_0;
10+
11+ a0 (int a) :
12+ a_0 (a)
13+ {}
14+
15+ a0 (const a0&) = default ;
16+ a0& operator =(const a0&) = default ;
17+
18+ a0 (a0&&) = default ;
19+ a0& operator =(a0&&) = default ;
20+
21+ virtual ~a0 () = default ;
22+ };
23+
24+ struct a1 : public a0 {
25+ int a_1;
26+
27+ a1 (int a) :
28+ a0 (a),
29+ a_1 (a)
30+ {}
31+ };
32+ } // namespace
33+
34+ namespace {
35+ const tst::set set (" unique_ref" , [](tst::suite& suite) {
36+ static_assert (
37+ !std::is_constructible_v<utki::unique_ref<std::string>>,
38+ " unique_ref must not be default constructible"
39+ " because unique_ref cannot be nullptr"
40+ );
41+
42+ static_assert (
43+ !std::is_convertible_v<std::unique_ptr<std::string>, utki::unique_ref<std::string>>,
44+ " unique_ptr must not be convertible to unique_ref"
45+ " because shared_ptr can be nullptr, but unique_ref cannot"
46+ );
47+
48+ static_assert (
49+ !std::is_copy_constructible_v<utki::unique_ref<std::string>>,
50+ " unique_ref must not be copy constructible"
51+ );
52+
53+ static_assert (std::is_move_constructible_v<utki::unique_ref<std::string>>, " unique_ref must be move constructible" );
54+
55+ suite.add (" constructor__unique_ptr" , []() {
56+ auto up = std::make_unique<a1>(3 );
57+
58+ tst::check_eq (up->a_1 , 3 , SL);
59+
60+ auto ur = utki::unique_ref (std::move (up));
61+
62+ tst::check (!up, SL);
63+ tst::check_eq (ur.get ().a_1 , 3 , SL);
64+ });
65+
66+ suite.add (" get" , []() {
67+ utki::unique_ref<std::string> ur = utki::make_unique<std::string>(etalon);
68+
69+ tst::check_eq (ur.get (), etalon, SL);
70+ });
71+
72+ suite.add (" const_get" , []() {
73+ const utki::unique_ref<std::string> ur = utki::make_unique<std::string>(etalon);
74+
75+ tst::check_eq (ur.get (), etalon, SL);
76+
77+ ur.get ().append (" !" );
78+
79+ tst::check_eq (etalon + " !" , ur.get (), SL);
80+ });
81+
82+ suite.add (" operator_convert_to_reference" , []() {
83+ utki::unique_ref<std::string> ur = utki::make_unique<std::string>(etalon);
84+
85+ [](std::string& s) {
86+ tst::check_eq (s, etalon, SL);
87+ }(ur);
88+
89+ [](const std::string& s) {
90+ tst::check_eq (s, etalon, SL);
91+ }(ur);
92+ });
93+
94+ suite.add (" operator_convert_to_reference_const" , []() {
95+ utki::unique_ref<const std::string> ur = utki::make_unique<std::string>(etalon);
96+
97+ [](const std::string& s) {
98+ tst::check_eq (s, etalon, SL);
99+ }(ur);
100+ });
101+
102+ suite.add (" const_autocast" , []() {
103+ utki::unique_ref<const std::string> sr = utki::make_unique<std::string>(etalon);
104+
105+ tst::check_eq (sr.get (), etalon, SL);
106+ });
107+
108+ suite.add (" downcast" , []() {
109+ utki::unique_ref<a0> sr = utki::make_unique<a1>(2 );
110+
111+ tst::check_eq (sr.get ().a_0 , 2 , SL);
112+ });
113+
114+ suite.add (" const_downcast" , []() {
115+ utki::unique_ref<const a0> sr = utki::make_unique<a1>(2 );
116+
117+ tst::check_eq (sr.get ().a_0 , 2 , SL);
118+ });
119+
120+ suite.add (" move_constructor" , []() {
121+ auto a = utki::make_unique<a1>(13 );
122+
123+ tst::check_eq (a.get ().a_0 , 13 , SL);
124+
125+ decltype (a) b (std::move (a));
126+
127+ tst::check_eq (b.get ().a_0 , 13 , SL);
128+ });
129+
130+ suite.add (" move_assignment" , []() {
131+ auto a = utki::make_unique<a1>(13 );
132+
133+ tst::check_eq (a.get ().a_0 , 13 , SL);
134+
135+ auto b = utki::make_unique<a1>(10 );
136+
137+ tst::check_eq (b.get ().a_0 , 10 , SL);
138+
139+ b = std::move (a);
140+
141+ tst::check_eq (b.get ().a_0 , 13 , SL);
142+ });
143+
144+ suite.add (" move_constructible_and_move_assignable" , []() {
145+ std::vector<utki::unique_ref<a0>> vec;
146+ vec.emplace_back (utki::make_unique<a1>(1 ));
147+ vec.emplace_back (utki::make_unique<a1>(2 ));
148+ vec.emplace_back (utki::make_unique<a1>(3 ));
149+
150+ tst::check_eq (vec[0 ].get ().a_0 , 1 , SL);
151+ tst::check_eq (vec[1 ].get ().a_0 , 2 , SL);
152+ tst::check_eq (vec[2 ].get ().a_0 , 3 , SL);
153+
154+ // std::rotate requires container element type to be
155+ // MoveAssignable and MoveConstructible
156+ #if CFG_CPP >= 20
157+ std::ranges::rotate (vec.begin (), std::next (vec.begin ()), vec.end ());
158+ #else
159+ std::rotate (vec.begin (), std::next (vec.begin ()), vec.end ());
160+ #endif
161+
162+ tst::check_eq (vec[0 ].get ().a_0 , 2 , SL);
163+ tst::check_eq (vec[1 ].get ().a_0 , 3 , SL);
164+ tst::check_eq (vec[2 ].get ().a_0 , 1 , SL);
165+ });
166+ });
167+ } // namespace
0 commit comments