2026-01-29 14:56:15 +00:00
/*
2026-07-24 13:24:40 +00:00
* ver . 1.8 .2
2026-01-29 14:56:15 +00:00
* ( c ) П р о е к т " SimStr " , А л е к с а н д р О р е ф к о в orefkov @ gmail . com
* Т е с т ы simstr
* ( c ) Project " SimStr " , Aleksandr Orefkov orefkov @ gmail . com
* Test of simstr
*/
# include "../include/simstr/strexpr.h"
# include <gtest/gtest.h>
# include <format>
# include <list>
using namespace std : : literals ;
namespace simstr : : tests {
/*!
* @ ru
* @ defgroup ConvertToStrExpr К о н в е р т а ц и я т и п о в в в с т р о к о в ы е в ы р а ж е н и я
* Р а з л и ч н ы е с п о с о б ы к о н в е р т а ц и и т и п о в в с т р о к о в ы е в ы р а ж е н и я .
* Е с л и в ы р е а л и з у е т е о д и н ( и т о л ь к о о д и н ) и з с п о с о б о в п р е о б р а з о в а н и я в а ш е г о т и п а в с т р о к о в о е в ы р а ж е н и е ,
* т о с м о ж е т е и с п о л ь з о в а т ь в а ш т и п н а п р я м у ю в о п е р а ц и я х к о н к а т е н а ц и и с о с т р о к о в ы м и в ы р а ж е н и я м и и к а к
* а р г у м е н т ы в ф у н к ц и я х ` e_concat ` и ` e_subst ` .
* @ en
* @ defgroup ConvertToStrExpr Converting types to string expressions
* Various ways to convert types to string expressions .
* If you implement one ( and only one ) of the ways to convert your type to a string expression ,
* then you can use your type directly in concatenation operations with string expressions and how
* arguments in the ` e_concat ` and ` e_subst ` functions .
*/
/*!
* @ ingroup ConvertToStrExpr
* @ ru @ page method1 С п о с о б 1
* П р о с т о р е а л и з у й т е в с в о ё м т и п е т р е б о в а н и я , ч т о б ы о н я в л я л с я с т р о к о в ы м в ы р а ж е н и е м .
* @ en @ page method1 Method 1
* Just implement the requirement in your type that it be a string expression .
* @ ru @ par П р и м е р :
* @ en @ par Example :
* @ ~
* @ snippet test_tostrexpr . cpp Method1
*/
//! [Method1]
struct add_exclamation {
ssa text_ ;
unsigned count_ ;
// symb_type
using symb_type = char ;
// length
size_t length ( ) const noexcept {
return text_ . length ( ) + count_ ;
}
// place
char * place ( char * ptr ) const noexcept {
ptr = text_ . place ( ptr ) ;
std : : char_traits < char > : : assign ( ptr , count_ , ' ! ' ) ;
return ptr + count_ ;
}
} ;
TEST ( ToStrExpr , CheckExclamation ) {
std : : string test = " Msg is < " + add_exclamation { " Happy Birthday " , 5 } + " > " ;
EXPECT_EQ ( test , " Msg is <Happy Birthday!!!!!> " ) ;
add_exclamation msg { " Happy Birthday " , 3 } ;
test = e_concat ( " " , " Msg is < " , msg , " > " ) ;
EXPECT_EQ ( test , " Msg is <Happy Birthday!!!> " ) ;
const add_exclamation cmsg { " Happy Birthday " , 0 } ;
2026-02-03 07:38:21 +00:00
test = e_subst ( " Msg is <{}> " , cmsg ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( test , " Msg is <Happy Birthday> " ) ;
}
//! [Method1]
/*!
* @ ingroup ConvertToStrExpr
* @ ru @ page method2 С п о с о б 2
* С о з д а й т е т и п - о б ё р т к у , к о т о р ы й я в л я е т с я с т р о к о в ы м в ы р а ж е н и е м и м о ж е т и н и ц и а л и з и р о в а т ь с я
* в а ш и м т и п о м . П о с л е з а д а й т е и х с о о т в е т с т в и е с п о м о щ ь ю с п е ц и а л и з а ц и и ш а б л о н а ` convert_to_strexpr ` .
* @ en @ page method2 Method 2
* Create a wrapper type that is a string expression and can be initialized
* your type . Then set their correspondence using the ` convert_to_strexpr ` template specialization .
* @ ru @ par П р и м е р :
* @ en @ par Example :
* @ ~
* @ snippet test_tostrexpr . cpp Method2
*/
//! [Method2]
// Тип / Type
struct car_info {
std : : string model ;
int year ;
} ;
// Обёртка для превращения е г о в строковое выражение
// Wrapper to turn it into a string expression
struct car_info_expr {
const car_info & car_ ;
expr_num < char , int > year ;
car_info_expr ( const car_info & car ) : car_ ( car ) , year ( car . year ) { }
inline static constexpr ssa ModelTag = " Model: " ;
inline static constexpr ssa YearTag = " , Year: " ;
using symb_type = char ;
size_t length ( ) const {
return ModelTag . length ( ) + car_ . model . length ( ) + YearTag . length ( ) + year . length ( ) ;
}
char * place ( char * ptr ) const {
ptr = ModelTag . place ( ptr ) ;
std : : char_traits < char > : : copy ( ptr , car_ . model . data ( ) , car_ . model . length ( ) ) ;
ptr + = car_ . model . length ( ) ;
ptr = YearTag . place ( ptr ) ;
return year . place ( ptr ) ;
}
} ;
} // namespace simstr::tests
namespace simstr {
// Специализируем шаблон, задавая соответствие типа и е г о обёртки
// Specialize the template by specifying a match between the type and its wrapper
template < >
struct convert_to_strexpr < char , tests : : car_info > {
// Указываем тип, который будет "обёрткой" для нашего типа
// Specify the type that will be a "wrapper" for our type
using type = tests : : car_info_expr ;
} ;
} // namespace simstr
namespace simstr : : tests {
TEST ( ToStrExpr , CheckCarInfo ) {
car_info ci { " Ford " , 2020 } ;
std : : string test = " Car is < " _ss + ci + " > " ;
EXPECT_EQ ( test , " Car is <Model: Ford, Year: 2020> " ) ;
ci . year + + ;
test = e_concat ( " " , " Car is < " , ci , " > " ) ;
EXPECT_EQ ( test , " Car is <Model: Ford, Year: 2021> " ) ;
ci . year + + ;
2026-02-03 07:38:21 +00:00
test = e_subst ( " Car is <{}> " , ci ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( test , " Car is <Model: Ford, Year: 2022> " ) ;
}
//! [Method2]
/*!
* @ ingroup ConvertToStrExpr
* @ ru @ page method3 С п о с о б 3
* С п е ц и а л и з и р у й т е ш а б л о н ` convert_to_strexpr ` д л я в а ш е г о т и п а и с о з д а й т е в н ё м с т а т и ч е с к у ю
* ф у н к ц и ю ` convert ` , п р и н и м а ю щ у ю в а ш о б ъ е к т и в о з в р а щ а ю щ у ю с т р о к о в о е в ы р а ж е н и е , с т р о к о в ы й о б ъ е к т
* simstr и л и std : : basic_string .
* @ en @ page method3 Method 3
* Specialize the ` convert_to_strexpr ` template for your type and create a static
* ` convert ` function in it that takes your object and returns a string expression , a simstr string object ,
* or std : : basic_string .
* @ ru @ par П р и м е р :
* @ en @ par Example :
* @ ~
* @ snippet test_tostrexpr . cpp Method3
*/
//! [Method3]
struct animal {
std : : string name_ ;
std : : string sound_ ;
} ;
} //namespace simstr::tests
namespace simstr {
// Специализируем шаблон, задавая соответствие типа и е г о обёртки
// Specialize the template by specifying a match between the type and its wrapper
template < >
struct convert_to_strexpr < char , tests : : animal > {
// Создаём функцию `convert`, которая вернёт строковое представление объекта
// Create a function `convert`, that will return a string representation of the object
static auto convert ( const tests : : animal & a ) {
// Так делать нельзя - операция + складывает в выражение ссылки на временные объекты,
// которые разрушаются после ";", и возвращать такой объект нельзя.
// This can't be done - the operator+ adds references to temporary objects to the expression,
// which are destroyed after ";", and such an object cannot be returned.
//return "Animal: " + a.name_ + ", Sound: " + a.sound_;
// А вот такой можно - он не хранит ссылки на временные объекты
// But this one is possible - it doesn't store references to temporary objects
return e_concat ( " " , " Animal: " , a . name_ , " , Sound: " , a . sound_ ) ;
// Также можно возвращать просто std::string, stringa, lstringa
// You can also return just std::string, stringa, lstringa
}
} ;
} //namespace simstr
namespace simstr : : tests {
TEST ( ToStrExpr , CheckAnimal ) {
animal cat { " Cat " , " Meow " } ;
std : : string test = " < " _ss + cat + " > " ;
EXPECT_EQ ( test , " <Animal: Cat, Sound: Meow> " ) ;
const animal dog { " Dog " , " Woof " } ;
test = e_concat ( " " , " < " , dog , " > " ) ;
EXPECT_EQ ( test , " <Animal: Dog, Sound: Woof> " ) ;
2026-02-03 07:38:21 +00:00
test = e_subst ( " \\ _{}_/ " , animal { " Snake " , " Pssstt " } ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( test , " \\ _Animal: Snake, Sound: Pssstt_/ " ) ;
}
//! [Method3]
/*!
* @ ingroup ConvertToStrExpr
* @ ru @ page method4 С п о с о б 4
* П р о с т о в с в о ё м т и п е с д е л а й т е ф у н к ц и ю ` template < typename K > auto to_strexpr ( ) const ` , к о т о р а я в о з в р а щ а е т
* с т р о к о в о е в ы р а ж е н и е и л и с т р о к о в ы й о б ъ е к т .
* @ en @ page method4 Method 4
* Simply create a ` template < typename K > auto to_strexpr ( ) const ` function in your type that returns a
* string expression or string object .
* @ ru @ par П р и м е р :
* @ en @ par Example :
* @ ~
* @ snippet test_tostrexpr . cpp Method4
*/
//! [Method4]
struct test {
int number ;
int from ;
// Сделаем две отдельные реализации: для char (попроще) и для остальных типов (там придётся возвращать не литералы, а simple_str, и требуется копия)
// Let's make two separate implementations: for char (simpler) and for other types (there we'll have to return not literals, but simple_str, and a copy is required)
template < typename K > requires ( std : : is_same_v < K , char > )
auto to_strexpr ( ) const {
return e_concat ( " " , " test " , number , " from " , from ) ;
}
template < typename K > requires ( ! std : : is_same_v < K , char > )
auto to_strexpr ( ) const {
// uni_string возвращает локальный объект, а ссылку на них нельзя возвращать из функции,
// поэтому в e_concat надо форсировать сохранение по копии, а не по ссылке.
// uni_string returns a local object, and references to them cannot be returned from a function,
// so in e_concat we need to force saving by copy, not by reference.
return e_concat ( force_copy { empty_expr < K > { } } , force_copy { uni_string ( K , " test " ) } , number , force_copy { uni_string ( K , " from " ) } , from ) ;
}
} ;
TEST ( ToStrExpr , CheckTest ) {
test t1 { 1 , 10 } ;
std : : string t = " Begin < " _ss + t1 + " > " ;
EXPECT_EQ ( t , " Begin <test 1 from 10> " ) ;
const test t2 { 8 , 12 } ;
t = e_concat ( " " , " < " , t2 , " > " ) ;
EXPECT_EQ ( t , " <test 8 from 12> " ) ;
2026-02-03 07:38:21 +00:00
t = e_subst ( " <{}> " , test { 99 , 100 } ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( t , " <test 99 from 100> " ) ;
// Проверим работу для не char
// Let's check the work for non-char
std : : wstring wt = L " aaa " _ss + test { 99 , 100 } ;
EXPECT_EQ ( wt , L " aaa test 99 from 100 " ) ;
std : : u16string ut = u " aaa " _ss + test { 99 , 100 } ;
EXPECT_EQ ( ut , u " aaa test 99 from 100 " ) ;
}
//! [Method4]
TEST ( ToStrExpr , ConcatCustom ) {
std : : string tt ;
std : : string c = e_concat ( eea + " , " + " " , u8 " bb " , tt , 1 , e_if ( true , " -- " ) , e_hex < HexFlags : : Short > ( 16 ) , 1.2 , test { 10 , 30 } ) ;
EXPECT_EQ ( c , " bb, , 1, --, 0x10, 1.2, test 10 from 30 " ) ;
std : : string_view text = " testes " ;
int count = 10 ;
std : : string t = e_concat ( " " , text , " = " , count , " times. " ) ;
EXPECT_EQ ( t , " testes = 10 times. " ) ;
}
TEST ( ToStrExpr , SubstCustom ) {
const auto ttt = " test " _ss ;
int ii = 3 ;
const test tr { 10 , 10 } ;
2026-02-03 07:38:21 +00:00
std : : string t = e_subst ( " Test {{--}} {}={}, {} " , ttt , tr , ii ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( t , " Test {--} test=test 10 from 10, 3 " ) ;
2026-02-03 07:38:21 +00:00
t = e_subst ( " Test {2}={1}, {2}, {1} " , " test " , 2 ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( t , " Test 2=test, 2, test " ) ;
2026-02-03 07:38:21 +00:00
std : : u16string u16t = e_subst ( u " Test {}={}, {} " , u " test " , 2 , u " test " sv ) ;
2026-01-29 14:56:15 +00:00
EXPECT_EQ ( u16t , u " Test test=2, test " ) ;
}
2026-02-03 07:38:21 +00:00
2026-01-29 14:56:15 +00:00
} // namespace simstr::tests