Skip to content

Commit 08845b7

Browse files
venikSasha Nikiforov
andauthored
Add unittests for arg_stream and some other minor fixes (#144)
* add unittest for arg_stream and some other minor fixes * address SeanP's comments and fix MSVS errors --------- Co-authored-by: Sasha Nikiforov <nikiforo@adobe.com>
1 parent eb3b586 commit 08845b7

File tree

7 files changed

+266
-24
lines changed

7 files changed

+266
-24
lines changed

adobe/arg_stream.hpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#include <boost/utility/enable_if.hpp>
2828

2929
#include <adobe/type_inspection.hpp> // ADOBE_HAS_TYPE/ADOBE_HAS_MEMBER
30+
#include <adobe/typeinfo.hpp>
3031

3132
#include <functional>
33+
#include <type_traits>
3234

3335
namespace adobe {
3436

@@ -109,17 +111,15 @@ struct traits {
109111

110112

111113
namespace detail {
112-
template <class ArgStream>
113-
static bool
114-
eof_check(ArgStream& as,
115-
typename boost::enable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = 0) {
114+
template <class ArgStream,
115+
typename boost::enable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = nullptr>
116+
static bool eof_check(ArgStream& as) {
116117
return as.eof();
117118
}
118119

119-
template <class ArgStream>
120-
static bool eof_check(
121-
ArgStream& as,
122-
typename boost::disable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = 0) {
120+
template <class ArgStream,
121+
typename boost::disable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = nullptr>
122+
static bool eof_check(ArgStream& as) {
123123
return false;
124124
}
125125

@@ -165,12 +165,12 @@ compile.
165165
*/
166166
template <typename R, typename ArgStream>
167167
R get_next_arg(ArgStream const& as) {
168-
return as.get_next_arg<R>();
168+
return as.template get_next_arg<R>();
169169
}
170170
// specialize these or let them fallback to the above specialization
171171
template <typename R, typename ArgStream>
172172
R get_next_arg(ArgStream& as) {
173-
return as.get_next_arg<R>();
173+
return as.template get_next_arg<R>();
174174
}
175175
template <typename R, typename ArgStream>
176176
R get_next_arg(ArgStream* as) {
@@ -289,7 +289,7 @@ typename result_type<F>::type call(T* that, F f, ArgStream& astream) {
289289
type,
290290
typename boost::mpl::end<boost::function_types::parameter_types<
291291
typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_>>>::type>::
292-
template apply(f, astream, boost::fusion::push_back(args, that));
292+
apply(f, astream, boost::fusion::push_back(args, that));
293293
}
294294

295295

@@ -321,13 +321,13 @@ struct chain {
321321
T get_next_arg() {
322322
if (!eof(first)) {
323323
try {
324-
return first->get_next_arg<T>();
324+
return first->template get_next_arg<T>();
325325
} catch (arg_stream::no_more_args&) {
326326
first = 0;
327327
}
328328
}
329329

330-
return second->get_next_arg<T>();
330+
return second->template get_next_arg<T>();
331331
}
332332

333333
bool eof() const { return eof(first) && eof(second); }
@@ -385,16 +385,16 @@ struct single {
385385

386386
bool eof() { return repeat == 0; }
387387

388-
template <typename R>
388+
template <typename R,
389+
typename std::enable_if<std::is_convertible_v<value_type, R>>::type* dummy = nullptr>
389390
R convert_or_throw(
390-
value_type& value,
391-
typename boost::enable_if<boost::is_convertible<value_type, R>>::type* dummy = 0) {
391+
value_type& value) {
392392
return R(value);
393393
}
394-
template <typename R>
394+
template <typename R,
395+
typename std::enable_if<!std::is_convertible_v<value_type, R>>::type* dummy = nullptr>
395396
R convert_or_throw(
396-
value_type& value,
397-
typename boost::disable_if<boost::is_convertible<value_type, R>>::type* dummy = 0) {
397+
value_type& value) {
398398
throw adobe::bad_cast();
399399
return *(R*)value;
400400
}

adobe/config.hpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,33 @@
101101

102102
/**************************************************************************************************/
103103

104-
#endif
104+
#define ASL_CPP_VERSION(X) (ASL_CPP_VERSION_PRIVATE() == (X))
105+
#define ASL_CPP_VERSION_LESS_THAN(X) (ASL_CPP_VERSION_PRIVATE() < (X))
106+
#define ASL_CPP_VERSION_AT_LEAST(X) (ASL_CPP_VERSION_PRIVATE() >= (X))
107+
108+
// Check C++ language standard, e.g. C++17 vs. C++20/23.
109+
//
110+
// Note that on Windows the value for __cplusplus is only set properly if /Zc:__cplusplus is set.
111+
// This should be the case with the most projects setup but we're not taking any chances.
112+
// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
113+
//
114+
// For MSVS for now there is no c++23 only /std:c++latest which is
115+
// "It's set to a higher, unspecified value when the /std:c++latest option is specified."
116+
// Newer compiler has /std:c++23preview, but we are not using it yet.
117+
#if (defined(__cplusplus) && __cplusplus >= 202302L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L)
118+
#define ASL_CPP_VERSION_PRIVATE() 23
119+
#elif (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
120+
#define ASL_CPP_VERSION_PRIVATE() 20
121+
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
122+
#define ASL_CPP_VERSION_PRIVATE() 17
123+
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
124+
#define ASL_CPP_VERSION_PRIVATE() 14
125+
#else
126+
// #warning Unknown version of C++, assuming C++23.
127+
#define ASL_CPP_VERSION_PRIVATE() 23
128+
#endif // (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
129+
130+
/**************************************************************************************************/
131+
#endif // #define ADOBE_CONFIG_HPP
105132

106133
/**************************************************************************************************/

adobe/serializable.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
namespace adobe {
2424

25-
#if __cplusplus < 202002L
25+
#if ASL_CPP_VERSION_LESS_THAN(20)
2626

2727
/**************************************************************************************************/
2828

@@ -66,15 +66,15 @@ template <class T>
6666
inline typename std::enable_if<!has_ostream_insertion<T>::value>::type
6767
ostream_insertion(std::ostream&, const T&) {}
6868

69-
#else // __cplusplus < 202002L
69+
#else // ASL_CPP_VERSION_LESS_THAN(20)
7070

7171
template <class T>
7272
inline void ostream_insertion(std::ostream& s, const T& x) {
7373
if constexpr (requires { s << x; }) {
7474
s << x;
7575
}
7676
}
77-
#endif // __cplusplus < 202002L
77+
#endif // ASL_CPP_VERSION_LESS_THAN(20)
7878

7979
template <>
8080
inline void ostream_insertion<bool>(std::ostream& s, const bool& x) {

adobe/type_traits.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
#ifndef ADOBE_TYPE_TRAITS_HPP
1111
#define ADOBE_TYPE_TRAITS_HPP
1212

13+
#include <adobe/config.hpp>
14+
1315
#include <type_traits>
1416

1517
/**************************************************************************************************/
1618

1719
namespace adobe {
1820

19-
#if __cplusplus < 201703L
21+
#if ASL_CPP_VERSION_LESS_THAN(17)
2022

2123
template <class F, class... Args>
2224
using invoke_result_t = std::result_of_t<F(Args...)>;

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ add_subdirectory(adam_smoke)
5959
add_subdirectory(adam_tutorial)
6060
add_subdirectory(algorithm)
6161
add_subdirectory(any_regular)
62+
add_subdirectory(arg_stream)
6263
add_subdirectory(closed_hash)
6364
add_subdirectory(cmath)
6465
add_subdirectory(conversion)

test/arg_stream/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
asl_test(BOOST NAME arg_stream SOURCES arg_stream_test.cpp)
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
Copyright 2005-2013 Adobe Systems Incorporated
3+
Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
4+
or a copy at http://stlab.adobe.com/licenses.html)
5+
*/
6+
7+
/******************************************************************************/
8+
9+
// asl
10+
#include <adobe/arg_stream.hpp>
11+
12+
#include <adobe/config.hpp>
13+
14+
// boost
15+
#define BOOST_TEST_MAIN
16+
#include <boost/test/unit_test.hpp>
17+
18+
// std
19+
#include <string>
20+
21+
BOOST_AUTO_TEST_CASE(arg_stream_single_basic_functionality) {
22+
// Test basic construction and single use
23+
adobe::arg_stream::single<int> stream(42);
24+
25+
// Should not be at EOF initially
26+
BOOST_CHECK(!stream.eof());
27+
28+
// Get the value once
29+
int value = stream.get_next_arg<int>();
30+
BOOST_CHECK_EQUAL(value, 42);
31+
32+
// Should be at EOF after single use
33+
BOOST_CHECK(stream.eof());
34+
35+
// Should throw no_more_args if we try to get another arg
36+
BOOST_CHECK_THROW(stream.get_next_arg<int>(), adobe::arg_stream::no_more_args);
37+
}
38+
39+
BOOST_AUTO_TEST_CASE(arg_stream_single_multiple_count) {
40+
// Test with repeat count
41+
adobe::arg_stream::single<std::string> stream("hello", 3);
42+
43+
// Should not be at EOF initially
44+
BOOST_CHECK(!stream.eof());
45+
46+
// Get the value three times
47+
for (int i = 0; i < 3; ++i) {
48+
BOOST_CHECK(!stream.eof());
49+
std::string value = stream.get_next_arg<std::string>();
50+
BOOST_CHECK_EQUAL(value, "hello");
51+
}
52+
53+
// Should be at EOF after three uses
54+
BOOST_CHECK(stream.eof());
55+
56+
// Should throw no_more_args if we try to get another arg
57+
BOOST_CHECK_THROW(stream.get_next_arg<std::string>(), adobe::arg_stream::no_more_args);
58+
}
59+
60+
BOOST_AUTO_TEST_CASE(arg_stream_single_type_conversion) {
61+
// Test implicit type conversions
62+
adobe::arg_stream::single<int> stream(42);
63+
64+
// Convert int to double
65+
double d_value = stream.get_next_arg<double>();
66+
BOOST_CHECK_EQUAL(d_value, 42.0);
67+
}
68+
69+
BOOST_AUTO_TEST_CASE(arg_stream_single_zero_count) {
70+
// Test with zero repeat count
71+
adobe::arg_stream::single<int> stream(42, 0);
72+
73+
// Should be at EOF immediately
74+
BOOST_CHECK(stream.eof());
75+
76+
// Should throw no_more_args immediately
77+
BOOST_CHECK_THROW(stream.get_next_arg<int>(), adobe::arg_stream::no_more_args);
78+
}
79+
80+
BOOST_AUTO_TEST_CASE(arg_stream_single_copy_semantics) {
81+
// Test that the value is properly stored and accessed
82+
std::string original = "test_string";
83+
adobe::arg_stream::single<std::string> stream(original);
84+
85+
std::string retrieved = stream.get_next_arg<std::string>();
86+
BOOST_CHECK_EQUAL(retrieved, original);
87+
88+
// Original should be unchanged
89+
BOOST_CHECK_EQUAL(original, "test_string");
90+
}
91+
92+
BOOST_AUTO_TEST_CASE(arg_stream_single_reference_type) {
93+
// Test with reference types
94+
int original = 100;
95+
adobe::arg_stream::single<int> stream(original, 2);
96+
97+
// Modify original
98+
original = 200;
99+
100+
// Stream should still have the original value (100) since it stores by value
101+
int first = stream.get_next_arg<int>();
102+
int second = stream.get_next_arg<int>();
103+
BOOST_CHECK_EQUAL(first, 100);
104+
BOOST_CHECK_EQUAL(second, 100);
105+
}
106+
107+
// Test functions for call tests
108+
int add_two_ints(int a, int b) {
109+
return a + b;
110+
}
111+
112+
int add_three_ints(int a, int b, int c) {
113+
return a + b + c;
114+
}
115+
116+
double multiply_double_int(double d, int i) {
117+
return d * i;
118+
}
119+
120+
void void_function(int /* value */) {
121+
// Just consume the value, nothing to return
122+
}
123+
124+
std::string concat_strings(const std::string& a, const std::string& b) {
125+
return a + b;
126+
}
127+
128+
// Test class for member function tests
129+
class TestClass {
130+
public:
131+
int value;
132+
TestClass(int v) : value(v) {}
133+
134+
int add_to_value(int x) {
135+
return value + x;
136+
}
137+
138+
int multiply_values(int x, int y) {
139+
return value * x * y;
140+
}
141+
};
142+
143+
BOOST_AUTO_TEST_CASE(arg_stream_call_basic_function) {
144+
// Test calling a simple function with two arguments
145+
adobe::arg_stream::single<int> stream1(10, 2);
146+
147+
int result = adobe::arg_stream::call(add_two_ints, stream1);
148+
BOOST_CHECK_EQUAL(result, 20); // 10 + 10
149+
}
150+
151+
BOOST_AUTO_TEST_CASE(arg_stream_call_mixed_types) {
152+
// Test calling a function with mixed argument types
153+
adobe::arg_stream::single<double> double_stream(2.5);
154+
adobe::arg_stream::single<int> int_stream(4);
155+
156+
auto chained = adobe::arg_stream::make_chain(double_stream, int_stream);
157+
158+
double result = adobe::arg_stream::call(multiply_double_int, chained);
159+
BOOST_CHECK_EQUAL(result, 10.0); // 2.5 * 4
160+
}
161+
162+
BOOST_AUTO_TEST_CASE(arg_stream_call_void_function) {
163+
// Test calling a void function
164+
adobe::arg_stream::single<int> stream(42);
165+
166+
// Should not throw and should consume the argument
167+
adobe::arg_stream::call(void_function, stream);
168+
169+
// Stream should be exhausted
170+
BOOST_CHECK(stream.eof());
171+
}
172+
173+
BOOST_AUTO_TEST_CASE(arg_stream_call_string_function) {
174+
// Test calling a function with string arguments
175+
adobe::arg_stream::single<std::string> stream1("Hello");
176+
adobe::arg_stream::single<std::string> stream2(" World");
177+
178+
auto chained = adobe::arg_stream::make_chain(stream1, stream2);
179+
180+
std::string result = adobe::arg_stream::call(concat_strings, chained);
181+
BOOST_CHECK_EQUAL(result, "Hello World");
182+
}
183+
184+
BOOST_AUTO_TEST_CASE(arg_stream_call_member_function) {
185+
// Test calling member functions
186+
TestClass obj(5);
187+
adobe::arg_stream::single<int> stream(10);
188+
189+
int result = adobe::arg_stream::call(&obj, &TestClass::add_to_value, stream);
190+
BOOST_CHECK_EQUAL(result, 15); // 5 + 10
191+
}
192+
193+
BOOST_AUTO_TEST_CASE(arg_stream_call_member_function_multiple_args) {
194+
// Test calling member function with multiple arguments
195+
TestClass obj(2);
196+
adobe::arg_stream::single<int> stream1(3);
197+
adobe::arg_stream::single<int> stream2(4);
198+
199+
auto chained = adobe::arg_stream::make_chain(stream1, stream2);
200+
201+
int result = adobe::arg_stream::call(&obj, &TestClass::multiply_values, chained);
202+
BOOST_CHECK_EQUAL(result, 24); // 2 * 3 * 4
203+
}
204+
205+
BOOST_AUTO_TEST_CASE(arg_stream_call_insufficient_args) {
206+
// Test that call throws when there are insufficient arguments
207+
adobe::arg_stream::single<int> stream(10, 1); // Only one argument available
208+
209+
// Should throw no_more_args when trying to call a function requiring two arguments
210+
BOOST_CHECK_THROW(adobe::arg_stream::call(add_two_ints, stream), adobe::arg_stream::no_more_args);
211+
}

0 commit comments

Comments
 (0)