2018-12-20 14:18:07 +08:00
// sol3
// The MIT License (MIT)
2021-03-06 14:03:23 +08:00
// Copyright (c) 2013-2021 Rapptz, ThePhD and contributors
2018-12-20 14:18:07 +08:00
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# include "sol_test.hpp"
# include "common_classes.hpp"
2021-03-06 14:03:23 +08:00
# include <catch2/catch.hpp>
2018-12-20 14:18:07 +08:00
# include <iterator>
# include <vector>
# include <list>
# include <forward_list>
# include <map>
# include <deque>
# include <array>
# include <unordered_map>
# include <set>
# include <unordered_set>
2019-09-15 12:43:44 +08:00
inline namespace sol2_test_container_table {
template < typename T >
struct as_table_callable {
T * ptr ;
as_table_callable ( T & ref_ ) : ptr ( & ref_ ) {
}
auto operator ( ) ( ) const {
return sol : : as_table ( * ptr ) ;
}
} ;
} // namespace sol2_test_container_table
2018-12-20 14:18:07 +08:00
TEST_CASE ( " containers/vector table roundtrip " , " make sure vectors can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : vector < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : vector < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : vector < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/deque table roundtrip " , " make sure deques can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : deque < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : deque < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : deque < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/array table roundtrip " , " make sure arrays can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : array < int , 3 > v { { 1 , 2 , 3 } } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : array < int , 3 > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : array < int , 3 > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/list table roundtrip " , " make sure lists can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : list < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : list < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : list < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/forward_list table roundtrip " , " make sure forward_lists can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : forward_list < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : forward_list < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : forward_list < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/map table roundtrip " , " make sure maps can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : map < std : : string , int > v { { " a " , 1 } , { " b " , 2 } , { " c " , 3 } } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : map < std : : string , int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : map < std : : string , int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/unordered_map table roundtrip " , " make sure unordered_maps can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : unordered_map < std : : string , int > v { { " a " , 1 } , { " b " , 2 } , { " c " , 3 } } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : unordered_map < std : : string , int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : unordered_map < std : : string , int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/unordered_set table roundtrip " , " make sure unordered_sets can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : unordered_set < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : unordered_set < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : unordered_set < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/set table roundtrip " , " make sure sets can be round-tripped " ) {
sol : : state lua ;
2020-12-19 12:48:42 +08:00
std : : set < int > v { 1 , 2 , 3 } ;
2019-09-15 12:43:44 +08:00
lua . set_function ( " f " , as_table_callable < std : : set < int > > ( v ) ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " x = f() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : as_table_t < std : : set < int > > x = lua [ " x " ] ;
2019-02-17 06:27:03 +08:00
bool areequal = x . value ( ) = = v ;
2018-12-20 14:18:07 +08:00
REQUIRE ( areequal ) ;
}
TEST_CASE ( " containers/table conversions (lvalue) " , " test table conversions with as_table and nested, when not directly serializing a temporary / new value " ) {
sol : : state lua ;
auto f = [ ] ( ) {
std : : vector < std : : string > response_words ;
response_words . push_back ( " a " ) ;
response_words . push_back ( " b " ) ;
response_words . push_back ( " c " ) ;
return sol : : as_table ( response_words ) ;
} ;
auto g = [ ] ( ) {
std : : vector < std : : string > response_words ;
response_words . push_back ( " a " ) ;
response_words . push_back ( " b " ) ;
response_words . push_back ( " c " ) ;
return sol : : as_nested ( response_words ) ;
} ;
lua [ " f " ] = std : : ref ( f ) ;
lua [ " g " ] = std : : ref ( g ) ;
sol : : safe_function sff = lua [ " f " ] ;
sol : : safe_function sfg = lua [ " g " ] ;
sol : : table tf = sff ( ) ;
sol : : table tg = sfg ( ) ;
std : : string af = tf [ 1 ] ;
std : : string bf = tf [ 2 ] ;
std : : string cf = tf [ 3 ] ;
std : : string ag = tf [ 1 ] ;
std : : string bg = tf [ 2 ] ;
std : : string cg = tf [ 3 ] ;
REQUIRE ( tf . size ( ) = = 3 ) ;
REQUIRE ( af = = " a " ) ;
REQUIRE ( bf = = " b " ) ;
REQUIRE ( cf = = " c " ) ;
REQUIRE ( tg . size ( ) = = 3 ) ;
REQUIRE ( ag = = " a " ) ;
REQUIRE ( bg = = " b " ) ;
REQUIRE ( cg = = " c " ) ;
}
TEST_CASE ( " containers/table conversions (std::ref) " , " test table conversions with as_table and nested, when not directly serializing a temporary / new value " ) {
sol : : state lua ;
std : : vector < std : : string > response_words ;
response_words . push_back ( " a " ) ;
response_words . push_back ( " b " ) ;
response_words . push_back ( " c " ) ;
auto f = [ & response_words ] ( ) { return sol : : as_table ( std : : ref ( response_words ) ) ; } ;
auto g = [ & response_words ] ( ) { return sol : : as_nested ( std : : ref ( response_words ) ) ; } ;
lua [ " f " ] = std : : ref ( f ) ;
lua [ " g " ] = std : : ref ( g ) ;
sol : : safe_function sff = lua [ " f " ] ;
sol : : safe_function sfg = lua [ " g " ] ;
sol : : table tf = sff ( ) ;
sol : : table tg = sfg ( ) ;
std : : string af = tf [ 1 ] ;
std : : string bf = tf [ 2 ] ;
std : : string cf = tf [ 3 ] ;
std : : string ag = tf [ 1 ] ;
std : : string bg = tf [ 2 ] ;
std : : string cg = tf [ 3 ] ;
REQUIRE ( tf . size ( ) = = 3 ) ;
REQUIRE ( af = = " a " ) ;
REQUIRE ( bf = = " b " ) ;
REQUIRE ( cf = = " c " ) ;
REQUIRE ( tg . size ( ) = = 3 ) ;
REQUIRE ( ag = = " a " ) ;
REQUIRE ( bg = = " b " ) ;
REQUIRE ( cg = = " c " ) ;
}
TEST_CASE ( " containers/table conversion " , " test table conversions with as_table and nested " ) {
sol : : state lua ;
lua . open_libraries ( sol : : lib : : base ) ;
2020-12-19 12:48:42 +08:00
lua . set_function ( " bark " , [ ] ( ) { return sol : : as_nested ( std : : vector < std : : string > { " bark " , " woof " } ) ; } ) ;
2018-12-20 14:18:07 +08:00
2020-12-19 12:48:42 +08:00
lua . set_function ( " woof " , [ ] ( ) { return sol : : as_nested ( std : : vector < std : : string > { " bark " , " woof " } ) ; } ) ;
2018-12-20 14:18:07 +08:00
auto result1 = lua . safe_script ( " v1 = bark() " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
auto result2 = lua . safe_script ( " v2 = woof() " , sol : : script_pass_on_error ) ;
REQUIRE ( result2 . valid ( ) ) ;
sol : : as_table_t < std : : vector < std : : string > > as_table_strings = lua [ " v1 " ] ;
sol : : nested < std : : vector < std : : string > > nested_strings = lua [ " v2 " ] ;
2020-12-19 12:48:42 +08:00
std : : vector < std : : string > expected_values { " bark " , " woof " } ;
2019-02-17 06:27:03 +08:00
REQUIRE ( as_table_strings . value ( ) = = expected_values ) ;
REQUIRE ( nested_strings . value ( ) = = expected_values ) ;
2018-12-20 14:18:07 +08:00
}
TEST_CASE ( " containers/from table argument conversions " , " test table conversions without as_table and nested for function args " ) {
2020-12-19 12:48:42 +08:00
const std : : vector < std : : string > expected_values { " bark " , " woof " } ;
2018-12-20 14:18:07 +08:00
sol : : state lua ;
lua . open_libraries ( sol : : lib : : base ) ;
lua . set_function ( " f " , [ & ] ( std : : vector < std : : string > t ) { return t = = expected_values ; } ) ;
auto result0 = lua . safe_script ( " t = { \" bark \" , \" woof \" } " ) ;
REQUIRE ( result0 . valid ( ) ) ;
auto result1 = lua . safe_script ( " assert(f(t)) " , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
sol : : function f = lua [ " f " ] ;
sol : : table t = lua [ " t " ] ;
bool passed = f ( t ) ;
REQUIRE ( passed ) ;
}
TEST_CASE ( " containers/deeply nested " , " make sure nested works for deeply-nested C++ containers and works as advertised " ) {
typedef std : : map < const char * , std : : string > info_t ;
typedef std : : vector < info_t > info_vector ;
class ModList {
public :
info_vector list ;
ModList ( ) {
2020-12-19 12:48:42 +08:00
list . push_back ( info_t { { " a " , " b " } } ) ;
2018-12-20 14:18:07 +08:00
}
2019-03-10 23:09:52 +08:00
sol : : nested < info_vector & > getList ( ) {
return sol : : nested < info_vector & > ( list ) ;
}
2018-12-20 14:18:07 +08:00
} ;
sol : : state lua ;
lua . open_libraries ( sol : : lib : : base ) ;
lua . new_usertype < ModList > ( " ModList " , " getList " , & ModList : : getList ) ;
sol : : string_view code = R " (
mods = ModList . new ( )
local modlist = mods : getList ( )
print ( modlist [ 1 ] )
assert ( type ( modlist ) = = " table " )
assert ( type ( modlist [ 1 ] ) = = " table " )
) " ;
auto result1 = lua . safe_script ( code , sol : : script_pass_on_error ) ;
REQUIRE ( result1 . valid ( ) ) ;
}
2020-12-19 12:48:42 +08:00
TEST_CASE ( " containers/nested with optional " , " optionals should not change the behavior of getting or setting types such as nested " ) {
const std : : vector < int > color = { 1 , 2 , 3 , 0 } ;
sol : : state lua ;
sol : : optional < sol : : nested < std : : vector < int > > > maybe_color_no = lua [ " color " ] ;
lua [ " color " ] = color ;
sol : : optional < sol : : nested < std : : vector < int > > > maybe_color_yes = lua [ " color " ] ;
REQUIRE_FALSE ( maybe_color_no . has_value ( ) ) ;
REQUIRE ( maybe_color_yes . has_value ( ) ) ;
std : : vector < int > & color_yes = maybe_color_yes . value ( ) . value ( ) ;
REQUIRE ( color = = color_yes ) ;
}