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 "gtest/gtest.h"
8
9 #include "mozilla/Algorithm.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/ResultVariant.h"
12
13 #include <iterator>
14 #include <vector>
15
16 using namespace mozilla;
17 using std::begin;
18 using std::end;
19
20 namespace {
21 struct MoveOnly {
MoveOnly__anonca9ae1270111::MoveOnly22 explicit MoveOnly(int32_t aValue) : mValue{Some(aValue)} {}
23
24 MoveOnly(MoveOnly&&) = default;
25 MoveOnly& operator=(MoveOnly&&) = default;
26
27 Maybe<int32_t> mValue;
28 };
29
30 struct TestError {};
31
32 constexpr static int32_t arr1[3] = {1, 2, 3};
33 } // namespace
34
TEST(MFBT_Algorithm_TransformAbortOnErr,NoError)35 TEST(MFBT_Algorithm_TransformAbortOnErr, NoError)
36 {
37 std::vector<int64_t> out;
38 auto res = TransformAbortOnErr(
39 begin(arr1), end(arr1), std::back_inserter(out),
40 [](const int32_t value) -> Result<int64_t, TestError> {
41 return value * 10;
42 });
43 ASSERT_TRUE(res.isOk());
44
45 const std::vector<int64_t> expected = {10, 20, 30};
46 ASSERT_EQ(expected, out);
47 }
48
TEST(MFBT_Algorithm_TransformAbortOnErr,NoError_Range)49 TEST(MFBT_Algorithm_TransformAbortOnErr, NoError_Range)
50 {
51 std::vector<int64_t> out;
52 auto res = TransformAbortOnErr(
53 arr1, std::back_inserter(out),
54 [](const int32_t value) -> Result<int64_t, TestError> {
55 return value * 10;
56 });
57 ASSERT_TRUE(res.isOk());
58
59 const std::vector<int64_t> expected = {10, 20, 30};
60 ASSERT_EQ(expected, out);
61 }
62
TEST(MFBT_Algorithm_TransformAbortOnErr,ErrorOnFirst)63 TEST(MFBT_Algorithm_TransformAbortOnErr, ErrorOnFirst)
64 {
65 std::vector<int64_t> out;
66 auto res = TransformAbortOnErr(
67 begin(arr1), end(arr1), std::back_inserter(out),
68 [](const int32_t value) -> Result<int64_t, TestError> {
69 return Err(TestError{});
70 });
71 ASSERT_TRUE(res.isErr());
72 ASSERT_TRUE(out.empty());
73 }
74
TEST(MFBT_Algorithm_TransformAbortOnErr,ErrorOnOther)75 TEST(MFBT_Algorithm_TransformAbortOnErr, ErrorOnOther)
76 {
77 std::vector<int64_t> out;
78 auto res = TransformAbortOnErr(
79 begin(arr1), end(arr1), std::back_inserter(out),
80 [](const int32_t value) -> Result<int64_t, TestError> {
81 if (value > 2) {
82 return Err(TestError{});
83 }
84 return value * 10;
85 });
86 ASSERT_TRUE(res.isErr());
87
88 // XXX Should we assert on this, or is the content of out an implementation
89 // detail?
90 const std::vector<int64_t> expected = {10, 20};
91 ASSERT_EQ(expected, out);
92 }
93
TEST(MFBT_Algorithm_TransformAbortOnErr,ErrorOnOther_Move)94 TEST(MFBT_Algorithm_TransformAbortOnErr, ErrorOnOther_Move)
95 {
96 MoveOnly in[3] = {MoveOnly{1}, MoveOnly{2}, MoveOnly{3}};
97 std::vector<int64_t> out;
98 auto res = TransformAbortOnErr(
99 std::make_move_iterator(begin(in)), std::make_move_iterator(end(in)),
100 std::back_inserter(out),
101 [](MoveOnly value) -> Result<int64_t, TestError> {
102 if (*value.mValue > 1) {
103 return Err(TestError{});
104 }
105 return *value.mValue * 10;
106 });
107 ASSERT_TRUE(res.isErr());
108
109 ASSERT_FALSE(in[0].mValue);
110 ASSERT_FALSE(in[1].mValue);
111 ASSERT_TRUE(in[2].mValue);
112
113 // XXX Should we assert on this, or is the content of out an implementation
114 // detail?
115 const std::vector<int64_t> expected = {10};
116 ASSERT_EQ(expected, out);
117 }
118
TEST(MFBT_Algorithm_TransformIfAbortOnErr,NoError)119 TEST(MFBT_Algorithm_TransformIfAbortOnErr, NoError)
120 {
121 std::vector<int64_t> out;
122 auto res = TransformIfAbortOnErr(
123 begin(arr1), end(arr1), std::back_inserter(out),
124 [](const int32_t value) { return value % 2 == 1; },
125 [](const int32_t value) -> Result<int64_t, TestError> {
126 return value * 10;
127 });
128 ASSERT_TRUE(res.isOk());
129
130 const std::vector<int64_t> expected = {10, 30};
131 ASSERT_EQ(expected, out);
132 }
133
TEST(MFBT_Algorithm_TransformIfAbortOnErr,NoError_Range)134 TEST(MFBT_Algorithm_TransformIfAbortOnErr, NoError_Range)
135 {
136 std::vector<int64_t> out;
137 auto res = TransformIfAbortOnErr(
138 arr1, std::back_inserter(out),
139 [](const int32_t value) { return value % 2 == 1; },
140 [](const int32_t value) -> Result<int64_t, TestError> {
141 return value * 10;
142 });
143 ASSERT_TRUE(res.isOk());
144
145 const std::vector<int64_t> expected = {10, 30};
146 ASSERT_EQ(expected, out);
147 }
148
TEST(MFBT_Algorithm_TransformIfAbortOnErr,ErrorOnOther)149 TEST(MFBT_Algorithm_TransformIfAbortOnErr, ErrorOnOther)
150 {
151 std::vector<int64_t> out;
152 auto res = TransformIfAbortOnErr(
153 begin(arr1), end(arr1), std::back_inserter(out),
154 [](const int32_t value) { return value % 2 == 1; },
155 [](const int32_t value) -> Result<int64_t, TestError> {
156 if (value > 2) {
157 return Err(TestError{});
158 }
159 return value * 10;
160 });
161 ASSERT_TRUE(res.isErr());
162
163 const std::vector<int64_t> expected = {10};
164 ASSERT_EQ(expected, out);
165 }
166
TEST(MFBT_Algorithm_TransformIfAbortOnErr,ErrorOnOther_Move)167 TEST(MFBT_Algorithm_TransformIfAbortOnErr, ErrorOnOther_Move)
168 {
169 MoveOnly in[3] = {MoveOnly{1}, MoveOnly{2}, MoveOnly{3}};
170 std::vector<int64_t> out;
171 auto res = TransformIfAbortOnErr(
172 std::make_move_iterator(begin(in)), std::make_move_iterator(end(in)),
173 std::back_inserter(out),
174 [](const MoveOnly& value) { return *value.mValue % 2 == 1; },
175 [](MoveOnly value) -> Result<int64_t, TestError> {
176 if (*value.mValue > 1) {
177 return Err(TestError{});
178 }
179 return *value.mValue * 10;
180 });
181 ASSERT_TRUE(res.isErr());
182
183 ASSERT_FALSE(in[0].mValue);
184 ASSERT_TRUE(in[1].mValue);
185 ASSERT_FALSE(in[2].mValue);
186
187 // XXX Should we assert on this, or is the content of out an implementation
188 // detail?
189 const std::vector<int64_t> expected = {10};
190 ASSERT_EQ(expected, out);
191 }
192