Before you start
Make sure that you can compile and run framework tests as described at Configure, Build and Install.
Step by step guide
The userver framework allows to use it's non-coroutine parts by using the userver-universal
CMake target. It provides usefull utilities like utils::FastPimpl, utils::TrivialBiMap, JSON and YAML formats, utils::AnyMovable, cache::LruMap and many other utilities. See Universal for a list of available functions and classes.
Let's write a simple JSON to YAML converter with the help of userver-universal
.
Code
The implementation is quite straightforward. Include the necessary C++ Standard library and userver headers:
#include <iostream>
#include <string>
Write the logic for converting each of the JSON types to YAML type:
USERVER_NAMESPACE_BEGIN
yaml::Value Convert(const json::Value& json, parse::To<yaml::Value>) {
yaml::ValueBuilder yaml_vb;
if (json.IsBool()) {
yaml_vb = json.ConvertTo<bool>();
} else if (json.IsInt64()) {
yaml_vb = json.ConvertTo<int64_t>();
} else if (json.IsUInt64()) {
yaml_vb = json.ConvertTo<uint64_t>();
} else if (json.IsDouble()) {
yaml_vb = json.ConvertTo<double>();
} else if (json.IsString()) {
yaml_vb = json.ConvertTo<std::string>();
} else if (json.IsArray()) {
for (const auto& elem : json) {
yaml_vb.PushBack(elem.ConvertTo<yaml::Value>());
}
} else if (json.IsObject()) {
for (auto it = json.begin(); it != json.end(); ++it) {
yaml_vb[it.GetName()] = it->ConvertTo<yaml::Value>();
}
}
return yaml_vb.ExtractValue();
}
}
USERVER_NAMESPACE_END
Finally, read data from std::cin
, parse it as JSON, convert to YAML and output it as text:
int main() {
namespace formats = USERVER_NAMESPACE::formats;
std::cout << std::endl;
}
Build and Run
To build the sample, execute the following build steps at the userver root directory:
mkdir build_release
cd build_release
cmake -DCMAKE_BUILD_TYPE=Release ..
make userver-samples-json2yaml
After that a tool is compiled an it could be used:
bash
$ samples/json2yaml/userver-samples-json2yaml
{"key": {"nested-key": [1, 2.0, "hello!", {"key-again": 42}]}}
^D
key:
nested-key:
- 1
- 2
- hello!
- key-again: 42
Testing
The code could be tested using any of the unit-testing frameworks, like Boost.Test, GTest, and so forth.
However, to test the code with pytest
some additional setup should be done:
- Inform CMake about the test and that it should be started by Python. Pass the path to the CMake built binary to Python:
add_test(NAME "${PROJECT_NAME}-pytest"
COMMAND
"${TESTSUITE_PYTHON_BINARY}" -m pytest
"--test-binary=${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
- Add a fixture to
conftest.py
to get the path to the CMake built binary: import pytest
def pytest_addoption(parser) -> None:
group = parser.getgroup('userver')
group.addoption('--test-binary', type=str, help='Path to build utility.')
@pytest.fixture(scope='session')
def path_to_json2yaml(pytestconfig):
return pytestconfig.option.test_binary
- Write the test:
import subprocess
_EXPECTED_OUTPUT = """key:
nested-key:
- 1
- 2
- hello!
- key-again: 42
"""
def test_basic(path_to_json2yaml):
pipe = subprocess.Popen(
[path_to_json2yaml],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
)
stdout, stderr = pipe.communicate(
input=b'{"key":{"nested-key": [1, 2.0, "hello!", {"key-again": 42}]}}',
)
assert stdout.decode('utf-8') == _EXPECTED_OUTPUT, stderr
Full sources
See the full example at: