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