Skip to content

Commit

Permalink
Improve test coverage.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Apr 2, 2024
1 parent d1f75bf commit a292fc5
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 149 deletions.
102 changes: 1 addition & 101 deletions doc/All-Config-Functions.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
# All Config Functions

* [binary](#binary)
* [~~cbor~~](#cbor)
* [default](#default)
* [env](#env)
* [jaxn](#jaxn)
* [~~json~~](#json)
* [~~msgpack~~](#msgpack)
* [parse](#parse)
* [read](#read)
* [shell](#shell)
* [split](#split)
* [string](#string)
* [~~ubjson~~](#ubjson)

This page is the reference documentation for all included config functions.

Expand All @@ -39,32 +35,6 @@ foo = (binary "Hello, world!")
```


## ~~cbor~~

The `cbor` function parses binary data as [CBOR] and returns the resulting value.

#### Example taoCONFIG Input File

```
foo = (cbor $82f5f4)
```

#### Resulting JAXN Config Data

```javascript
{
foo: [
true,
false
]
}
```

Note that, in line with the JSON data model, only UTF-8 strings are supported as keys in CBOR mappings.

Note that `cbor` is frequently combined with `read` as in `foo = (cbor (read "filename.cbor"))`.


## default

The `default` function takes one or more arguments and returns the first one that is not a JSON `null`.
Expand Down Expand Up @@ -134,55 +104,6 @@ foo = (jaxn '[Infinity, $ff]')
Note that `jaxn` is frequently combined with `read` as in `foo = (jaxn (read "filename.jaxn"))`.


## ~~json~~

The `json` function parses string (or binary) data as [JSON] and returns the resulting value.
In the case of binary data the input is automatically converted to a string, including a check for valid UTF-8.

#### Example taoCONFIG Input File

```
foo = (json '["a","b"]')
```

#### Resulting JAXN Config Data

```javascript
{
foo: [
"a",
"b"
]
}
```

Note that `json` is frequently combined with `read` as in `foo = (json (read "filename.json"))`.


## ~~msgpack~~

The `msgpack` value extension parses binary data as [MsgPack] and returns the resulting value.

#### Example taoCONFIG Input File

```
foo = (msgpack $82a161c3a162c2)
```

#### Resulting JAXN Config Data

```javascript
{
foo: {
a: true,
b: false
}
}
```

Note that `msgpack` is frequently combined with `read` as in `foo = (msgpack (read "filename.msgpack"))`.


## parse

The `parse` function parses the given string as a single config value just "as if" the config file contained the string instead of the invocation of `parse`.
Expand Down Expand Up @@ -282,7 +203,7 @@ foo = (split "a b c ")

## string

The `string` function transforms a binary value into a string value.
The `string` function transforms a binary value into a string value and leaves string values unchanged.
It validates that the binary data is valid UTF-8 and produces an error if that is not the case.

#### Example taoCONFIG Input File
Expand All @@ -303,27 +224,6 @@ Note that the conversion from `binary` to `string` is automatic when the binary
The automatic conversion, too, checks whether the binary data is a valid UTF-8 sequence and throws an exception if that is not the case.


## ~~ubjson~~

The `ubjson` value function parses binary data as [UBJSON] and returns the resulting value.

#### Example taoCONFIG Input File

```
foo = (ubjson $4344)
```

#### Resulting JAXN Config Data

```javascript
{
foo: "D"
}
```

Note that `ubjson` is frequently combined with `read` as in `foo = (ubjson (read "filename.ubjson"))`.



Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey

Expand Down
7 changes: 2 additions & 5 deletions include/tao/config/internal/function_implementations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,9 @@ namespace tao::config::internal
return result;
}

[[nodiscard]] inline string_t string_function( const pegtl::position& p, const std::vector< std::byte >& bv )
[[nodiscard]] inline string_t string_function( const pegtl::position& p, const std::string& s )
{
if( !json::internal::validate_utf8_nothrow( std::string_view( reinterpret_cast< const char* >( bv.data() ), bv.size() ) ) ) {
throw pegtl::parse_error( "invalid utf8 in binary data", p );
}
return string_t( std::string( reinterpret_cast< const char* >( bv.data() ), bv.size() ), p );
return string_t( s, p );
}

// [[nodiscard]] inline json_t ubjson_function( const std::vector< std::byte >& bv )
Expand Down
8 changes: 4 additions & 4 deletions include/tao/config/internal/function_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ namespace tao::config::internal
}
};

[[nodiscard]] inline const entry& function_traits_value( array& f, const std::size_t i )
[[nodiscard]] inline const entry& function_traits_entry( array& f, const std::size_t i )
{
assert( f.array.size() > i );

Expand All @@ -75,7 +75,7 @@ namespace tao::config::internal
{
[[nodiscard]] static std::string get( array& f, const std::size_t i )
{
const entry& e = function_traits_value( f, i );
const entry& e = function_traits_entry( f, i );

if( e.is_string() ) {
return e.get_string();
Expand All @@ -84,7 +84,7 @@ namespace tao::config::internal
const std::vector< std::byte >& b = e.get_binary();
const std::string s( reinterpret_cast< const char* >( b.data() ), b.size() );
if( !json::internal::validate_utf8_nothrow( s ) ) {
throw pegtl::parse_error( "invalid utf-8 in binary data used as string argument", e.get_position() );
throw pegtl::parse_error( "invalid utf-8 in binary data used as string", e.get_position() );
}
return s;
}
Expand All @@ -97,7 +97,7 @@ namespace tao::config::internal
{
[[nodiscard]] static std::vector< std::byte > get( array& f, const std::size_t i )
{
const entry& e = function_traits_value( f, i );
const entry& e = function_traits_entry( f, i );

if( e.is_binary() ) {
return e.get_binary();
Expand Down
11 changes: 4 additions & 7 deletions include/tao/config/internal/function_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ namespace tao::config::internal
static_assert( !std::is_same_v< R, void > );

return function( [ x ]( entry& e ) {
array& f = e.get_array();
try {
decltype( auto ) a = function_traits< std::decay_t< A > >::get( f, 0 );
function_traits< std::decay_t< R > >::put( e, x( f.position, a ) );
array& f = e.get_array();
function_traits< std::decay_t< R > >::put( e, x( f.position, function_traits< std::decay_t< A > >::get( f, 0 ) ) );
}
catch( const arguments_unready& ) {
return false;
Expand All @@ -55,11 +54,9 @@ namespace tao::config::internal
static_assert( !std::is_same_v< R, void > );

return function( [ x ]( entry& e ) {
array& f = e.get_array();
try {
decltype( auto ) a = function_traits< std::decay_t< A > >::get( f, 0 );
decltype( auto ) b = function_traits< std::decay_t< B > >::get( f, 1 );
function_traits< std::decay_t< R > >::put( e, x( f.position, a, b ) );
array& f = e.get_array();
function_traits< std::decay_t< R > >::put( e, x( f.position, function_traits< std::decay_t< A > >::get( f, 0 ), function_traits< std::decay_t< B > >::get( f, 1 ) ) );
}
catch( const arguments_unready& ) {
return false;
Expand Down
24 changes: 14 additions & 10 deletions include/tao/config/internal/phase2_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,20 @@ namespace tao::config::internal

void process_parse_function( entry& e, array& a )
{
state st;
std::size_t i = 0;
const std::string s = function_traits< std::string >::get( a, i );
const key1 k = { key1_part( std::string( "\0", 1 ), a.position ) };
const key1_guard kg( st, key1( k ) );
pegtl::string_input< pegtl::tracking_mode::eager, pegtl_input_t::eol_t > in( s, __FUNCTION__ );
pegtl::parse_nested< rules::value, config_action >( a.position, static_cast< pegtl_input_t& >( in ), st, m_functions );
assert( st.root.object.size() == 1 );
assert( st.root.object.begin()->second.concat.size() == 1 );
e = st.root.object.begin()->second.concat.front(); // TODO: This is slightly hack-ish.
try {
state st;
std::size_t i = 0;
const std::string s = function_traits< std::string >::get( a, i );
const key1 k = { key1_part( std::string( "\0", 1 ), a.position ) };
const key1_guard kg( st, key1( k ) );
pegtl::string_input< pegtl::tracking_mode::eager, pegtl_input_t::eol_t > in( s, __FUNCTION__ );
pegtl::parse_nested< rules::value, config_action >( a.position, static_cast< pegtl_input_t& >( in ), st, m_functions );
assert( st.root.object.size() == 1 );
assert( st.root.object.begin()->second.concat.size() == 1 );
e = st.root.object.begin()->second.concat.front(); // TODO: This is slightly hack-ish.
}
catch( const arguments_unready& ) {
}
}
};

Expand Down
10 changes: 0 additions & 10 deletions include/tao/config/key_part.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,6 @@ namespace tao::config
return l.data == r.data;
}

[[nodiscard]] constexpr bool is_alpha( const int c ) noexcept
{
return ( ( 'a' <= c ) && ( c <= 'z' ) ) || ( ( 'A' <= c ) && ( c <= 'Z' ) );
}

[[nodiscard]] constexpr bool is_first( const int c ) noexcept
{
return is_alpha( c ) || ( c == '_' );
}

[[nodiscard]] inline bool is_identifier( const std::string& n )
{
using grammar = pegtl::seq< internal::rules::ident, pegtl::eof >;
Expand Down
2 changes: 2 additions & 0 deletions src/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ set(testsources
debug_traits.cpp
enumerations.cpp
failure.cpp
key.cpp
key_part.cpp
multi_line_string_position.cpp
parse_key1.cpp
parse_key.cpp
Expand Down
46 changes: 46 additions & 0 deletions src/test/config/key.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/config/

#include <sstream>
#include <string>

#include "test.hpp"

#include <tao/config/key.hpp>

namespace tao::config
{
void unit_test()
{
const std::string s0 = "foo.bar.42.\" \"";
const std::vector< key_part > kpv = { key_part( "foo" ), key_part( "bar" ), key_part( 42 ), key_part( " " ) };
const key k1( kpv.begin(), kpv.end() );
const key k2( "foo.bar.42.' '" );
const key k3 = { key_part( "foo" ), key_part( "bar" ), key_part( 42 ), key_part( " " ) };
key k4 = k3;
TAO_CONFIG_TEST_ASSERT( k1.size() == 4 );
TAO_CONFIG_TEST_ASSERT( k1 == k2 );
TAO_CONFIG_TEST_ASSERT( k1 == k3 );
TAO_CONFIG_TEST_ASSERT( k1.vector() == k2.vector() );
TAO_CONFIG_TEST_ASSERT( k1.vector() == k4.vector() );
const auto k5 = pop_front( k1 );
const auto k6 = pop_back( k1 );
TAO_CONFIG_TEST_ASSERT( k5.size() == 3 );
TAO_CONFIG_TEST_ASSERT( k6.size() == 3 );
TAO_CONFIG_TEST_ASSERT( k5 == key( "bar.42.' '" ) );
TAO_CONFIG_TEST_ASSERT( k6 == key( "foo.bar.42" ) );
const std::string s1 = to_string( k1 );
TAO_CONFIG_TEST_ASSERT( s1 == s0 );
std::ostringstream oss;
to_stream( oss, k1 );
TAO_CONFIG_TEST_ASSERT( oss.str() == s0 );
k4 = pop_back( k1 );
TAO_CONFIG_TEST_ASSERT( k4 + " " == k1 );
TAO_CONFIG_TEST_ASSERT( k4 + key_part( " " ) == k1 );
TAO_CONFIG_TEST_ASSERT( k4 + key( "\" \"" ) == k1 );
TAO_CONFIG_TEST_ASSERT( k1 + 123 == key( s0 + ".123" ) );
}

} // namespace tao::config

#include "main.hpp"
58 changes: 58 additions & 0 deletions src/test/config/key_part.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/config/

#include <sstream>
#include <string>

#include "test.hpp"

#include <tao/config/key_part.hpp>

namespace tao::config
{
void test_name1()
{
const std::string str = "foo";
const key_part p( str );
TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name );
TAO_CONFIG_TEST_ASSERT( p.get_name() == str );
TAO_CONFIG_TEST_ASSERT( to_string( p ) == str );
std::ostringstream oss;
to_stream( oss, p );
TAO_CONFIG_TEST_ASSERT( oss.str() == str );
}

void test_name2()
{
const std::string str = "+- ";
const key_part p( str );
TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name );
TAO_CONFIG_TEST_ASSERT( p.get_name() == str );
TAO_CONFIG_TEST_ASSERT( to_string( p ) == '"' + str + '"' );
std::ostringstream oss;
to_stream( oss, p );
TAO_CONFIG_TEST_ASSERT( oss.str() == '"' + str + '"' );
}

void test_index()
{
const std::size_t ind = 42;
const key_part p( ind );
TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::index );
TAO_CONFIG_TEST_ASSERT( p.get_index() == ind );
TAO_CONFIG_TEST_ASSERT( to_string( p ) == "42" );
std::ostringstream oss;
to_stream( oss, p );
TAO_CONFIG_TEST_ASSERT( oss.str() == "42" );
}

void unit_test()
{
test_name1();
test_name2();
test_index();
}

} // namespace tao::config

#include "main.hpp"
Loading

0 comments on commit a292fc5

Please sign in to comment.