diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index ef816fff19..d036604b04 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -1678,3 +1678,8 @@ class DateTimeImmutable implements DateTimeInterface { } function getenv(string $varname = '', bool $local_only = false): mixed; + +function yaml_emit_file(string $filename, mixed $data): bool; +function yaml_emit(mixed $data): string; +function yaml_parse_file(string $filename, int $pos = 0): mixed; +function yaml_parse(string $data, int $pos = 0): mixed; diff --git a/cmake/external-libraries.cmake b/cmake/external-libraries.cmake index f88954a907..5374e35ff9 100644 --- a/cmake/external-libraries.cmake +++ b/cmake/external-libraries.cmake @@ -91,3 +91,6 @@ if(APPLE) add_definitions(-DEPOLL_SHIM_LIB_DIR="${epoll_BINARY_DIR}/src") set(EPOLL_SHIM_LIB epoll-shim) endif() + +option(YAML "build yaml" OFF) +cmake_print_variables(YAML) diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index edd072a119..829f2578bc 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -57,6 +57,11 @@ prepend(KPHP_RUNTIME_PDO_PGSQL_SOURCES pdo/pgsql/ pgsql_pdo_emulated_statement.cpp) endif() +if (YAML) +prepend(KPHP_RUNTIME_YAML_SOURCES / + yaml.cpp) +endif() + prepend(KPHP_RUNTIME_SOURCES ${BASE_DIR}/runtime/ ${KPHP_RUNTIME_DATETIME_SOURCES} ${KPHP_RUNTIME_MEMORY_RESOURCE_SOURCES} @@ -67,6 +72,7 @@ prepend(KPHP_RUNTIME_SOURCES ${BASE_DIR}/runtime/ ${KPHP_RUNTIME_PDO_SOURCES} ${KPHP_RUNTIME_PDO_MYSQL_SOURCES} ${KPHP_RUNTIME_PDO_PGSQL_SOURCES} + ${KPHP_RUNTIME_YAML_SOURCES} allocator.cpp array_functions.cpp bcmath.cpp diff --git a/runtime/yaml.cpp b/runtime/yaml.cpp new file mode 100644 index 0000000000..0d63378250 --- /dev/null +++ b/runtime/yaml.cpp @@ -0,0 +1,197 @@ +#include + +#include "runtime/optional.h" +#include "runtime/streams.h" +#include "runtime/yaml.h" + +/* + * convert YAML::Node to mixed after parsing a YAML document into YAML::Node + */ +static void yaml_node_to_mixed(const YAML::Node &node, mixed &data, const string &source) noexcept { + data.clear(); // sets data to NULL + if (node.IsScalar()) { + const string string_data(node.as().c_str()); + // check whether the primitive is put in quotes in the source YAML + const bool string_data_has_quotes = + (source[node.Mark().pos] == '"' && source[node.Mark().pos + string_data.size() + 1] == '"') || + (source[node.Mark().pos] == '\'' && source[node.Mark().pos + string_data.size() + 1] == '\''); + // if so, it is a string + if (string_data_has_quotes) { + data = string_data; + } else if (string_data == string("true")) { + data = true; // "true" without quotes is boolean(1) + } else if (string_data == string("false")) { + data = false; // "false" without quotes is boolean(0) + } else if (string_data.is_int()) { + data = string_data.to_int(); + } else { + double float_data = 0.0; + if (string_data.try_to_float(&float_data)) { + data = float_data; + } else { + data = string_data; + } + } + } else if (node.size() == 0 && node.IsDefined() && !node.IsNull()) { + // if node is defined, is not null or scalar and has size 0, then it is an empty array + array empty_array; + data = empty_array; + } else if (node.IsSequence()) { + for (auto it = node.begin(); it != node.end(); ++it) { + mixed data_piece; + yaml_node_to_mixed(*it, data_piece, source); + data.push_back(data_piece); + } + } else if (node.IsMap()) { + for (const auto &it : node) { + mixed data_piece; + yaml_node_to_mixed(it.second, data_piece, source); + data.set_value(string(it.first.as().c_str()), data_piece); + } + } + // else node is Null or Undefined, so data is Null +} + +/* + * print tabs in quantity of nesting_level (used to print nested YAML entries) + */ +static string yaml_print_tabs(const int nesting_level) noexcept { + return string(2 * nesting_level, ' '); +} + +/* + * print the key of a YAML map entry + */ +static string yaml_print_key(const mixed &data_key) noexcept { + if (data_key.is_string()) { + return data_key.as_string(); + } + // key can not be an array; bool and float keys are cast to int + return string(data_key.as_int()); +} + +/* + * escape special characters in a string entry + */ +static string yaml_escape(const string &data) noexcept { + string escaped_data; + for (size_t i = 0; i < data.size(); ++i) { + const char& current_char = data[i]; + if (current_char == '\n') { // line feed + escaped_data.push_back('\\'); + escaped_data.push_back('n'); + } else if (current_char == '\b') { // backspace + escaped_data.push_back('\\'); + escaped_data.push_back('b'); + } else if (current_char == '\t') { // horizontal tab + escaped_data.push_back('\\'); + escaped_data.push_back('t'); + } else if (current_char == '\v') { // vertical tab + escaped_data.push_back('\\'); + escaped_data.push_back('v'); + } else if (current_char == '\"') { + escaped_data.push_back('\\'); + escaped_data.push_back('"'); + } else if (current_char == '\\') { + escaped_data.push_back('\\'); + escaped_data.push_back('\\'); + } else { + escaped_data.push_back(current_char); + } + } + return escaped_data; +} + +/* + * get a YAML representation of mixed in a string variable + */ +static void mixed_to_string(const mixed &data, string &string_data, const int nesting_level = 0) noexcept { + if (!data.is_array()) { + if (data.is_null()) { + string_data.push_back('~'); // tilda is a YAML representation of NULL + } else if (data.is_string()) { + string_data.push_back('"'); // cover string entry in double quotes + string_data.append(yaml_escape(data.as_string())); // escape special characters + string_data.push_back('"'); + } else if (data.is_int()) { + string_data.append(data.as_int()); + } else if (data.is_float()) { + string_data.append(data.as_double()); + } else if (data.is_bool()) { + const string bool_repr = (data.as_bool()) ? string("true") : string("false"); + string_data.append(bool_repr); + } + string_data.push_back('\n'); + return; + } + const array &data_array = data.as_array(); + if (data_array.empty()) { + string_data.append("[]\n"); // an empty array is represented as [] in YAML + return; + } + // check if an array has keys increasing by 1 starting from 0 + const bool data_array_is_vector = data_array.is_pseudo_vector(); + for (const auto &it : data_array) { + const mixed &data_piece = it.get_value(); + string_data.append(yaml_print_tabs(nesting_level)); + if (data_array_is_vector) { + string_data.push_back('-'); + } else { + string_data.append(yaml_print_key(it.get_key())); + string_data.push_back(':'); + } + if (data_piece.is_array() && !data_piece.as_array().empty()) { + // if an element of an array is also a non-empty array, print it on the next line + string_data.push_back('\n'); + } else { + // if an element of an array is a primitive or an empty array, print it after a space + string_data.push_back(' '); + } + // for entries of an array, increase nesting level + mixed_to_string(data_piece, string_data, nesting_level + 1); + } +} + +bool f$yaml_emit_file(const string &filename, const mixed &data) { + if (filename.empty()) { + php_warning("Filename cannot be empty"); + return false; + } + string emitted_data = f$yaml_emit(data); + Optional size = f$file_put_contents(filename, emitted_data); + if (size.is_false()) { + php_warning("Error while writing to file \"%s\"", filename.c_str()); + return false; + } + return true; +} + +string f$yaml_emit(const mixed &data) { + string string_data("---\n"); // beginning of a YAML document + mixed_to_string(data, string_data); + string_data.append("...\n"); // ending of a YAML document + return string_data; +} + +mixed f$yaml_parse_file(const string &filename, int pos) { + if (filename.empty()) { + php_warning("Filename cannot be empty"); + return false; + } + Optional data = f$file_get_contents(filename); + if (data.is_false()) { + php_warning("Error while reading file \"%s\"", filename.c_str()); + return false; + } + return f$yaml_parse(data.ref(), pos); +} + +mixed f$yaml_parse(const string &data, int pos) { + if (pos != 0) { + php_warning("Argument \"pos\" = %d. Values other than 0 are not supported yet. Setting to default (pos = 0)", pos); + } + YAML::Node node = YAML::Load(data.c_str()); + mixed parsed_data; + yaml_node_to_mixed(node, parsed_data, data); + return parsed_data; +} diff --git a/runtime/yaml.h b/runtime/yaml.h new file mode 100644 index 0000000000..cd03cdffbb --- /dev/null +++ b/runtime/yaml.h @@ -0,0 +1,11 @@ +#pragma once + +#include "runtime/kphp_core.h" + +bool f$yaml_emit_file(const string &filename, const mixed &data); + +string f$yaml_emit(const mixed &data); + +mixed f$yaml_parse_file(const string &filename, int pos = 0); + +mixed f$yaml_parse(const string &data, int pos = 0); diff --git a/tests/cpp/runtime/runtime-tests.cmake b/tests/cpp/runtime/runtime-tests.cmake index 731da98fe6..cf1401fdf5 100644 --- a/tests/cpp/runtime/runtime-tests.cmake +++ b/tests/cpp/runtime/runtime-tests.cmake @@ -1,4 +1,10 @@ +if (YAML) +prepend(RUNTIME_TESTS_YAML_SOURCES / + yaml-test.cpp) +endif() + prepend(RUNTIME_TESTS_SOURCES ${BASE_DIR}/tests/cpp/runtime/ + ${RUNTIME_TESTS_YAML_SOURCES} _runtime-tests-env.cpp allocator-malloc-replacement-test.cpp array-test.cpp diff --git a/tests/cpp/runtime/yaml-test.cpp b/tests/cpp/runtime/yaml-test.cpp new file mode 100644 index 0000000000..88f78030c3 --- /dev/null +++ b/tests/cpp/runtime/yaml-test.cpp @@ -0,0 +1,335 @@ +#include + +#include "runtime/files.h" +#include "runtime/yaml.h" + +TEST(yaml_test, test_yaml_string) { + mixed example = string("string"); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_string()); + ASSERT_TRUE(example.as_string() == result.as_string()); +} + +TEST(yaml_test, test_yaml_empty_string) { + mixed example = string(""); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_string()); + ASSERT_TRUE(example.as_string() == result.as_string()); +} + +TEST(yaml_test, test_yaml_int) { + mixed example = 13; + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_int()); + ASSERT_EQ(example.as_int(), result.as_int()); +} + +TEST(yaml_test, test_yaml_float) { + mixed example = 3.1416; + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_float()); + ASSERT_DOUBLE_EQ(example.as_double(), result.as_double()); +} + +TEST(yaml_test, test_yaml_int_as_string) { + mixed example = string("13"); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_string()); + ASSERT_EQ(example.as_string(), result.as_string()); +} + +TEST(yaml_test, test_yaml_float_as_string) { + mixed example = string("3.1416"); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_string()); + ASSERT_EQ(example.as_string(), result.as_string()); +} + +TEST(yaml_test, test_yaml_vector) { + mixed example; + example.push_back(string("string")); + example.push_back(13); + example.push_back(3.1416); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[0].is_string()); + ASSERT_TRUE(example[0].as_string() == result[0].as_string()); + ASSERT_TRUE(result[1].is_int()); + ASSERT_EQ(example[1].as_int(), result[1].as_int()); + ASSERT_TRUE(result[2].is_float()); + ASSERT_DOUBLE_EQ(example[2].as_double(), result[2].as_double()); +} + +TEST(yaml_test, test_yaml_vector_recursive) { + mixed example, copy; + example.push_back(string("string")); + example.push_back(13); + example.push_back(3.1416); + for (auto it = example.begin(); it != example.end(); ++it) { + copy.push_back(it.get_value()); + } + example.push_back(copy); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result[3].is_array()); + ASSERT_TRUE(result[3].as_array().is_pseudo_vector()); + ASSERT_TRUE(result[3][0].is_string()); + ASSERT_TRUE(example[3][0].as_string() == result[3][0].as_string()); + ASSERT_TRUE(result[3][1].is_int()); + ASSERT_EQ(example[3][1].as_int(), result[3][1].as_int()); + ASSERT_TRUE(result[3][2].is_float()); + ASSERT_DOUBLE_EQ(example[3][2].as_double(), result[3][2].as_double()); +} + +TEST(yaml_test, test_yaml_bool) { + mixed example; + example.push_back(true); + example.push_back(false); + example.push_back(string("true")); + example.push_back(string("false")); + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[0].is_bool()); + ASSERT_TRUE(example[0].as_bool() == result[0].as_bool()); + ASSERT_TRUE(result[1].is_bool()); + ASSERT_TRUE(example[1].as_bool() == result[1].as_bool()); + ASSERT_TRUE(result[2].is_string()); + ASSERT_TRUE(example[2].as_string() == result[2].as_string()); + ASSERT_TRUE(result[3].is_string()); + ASSERT_TRUE(example[3].as_string() == result[3].as_string()); +} + +TEST(yaml_test, test_yaml_map) { + mixed example; + example[string("first")] = string("string"); + example[string("second")] = 13; + example[string("third")] = 3.1416; + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_array()); + ASSERT_FALSE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[string("first")].is_string()); + ASSERT_TRUE(example[string("first")].as_string() == result[string("first")].as_string()); + ASSERT_TRUE(result[string("second")].is_int()); + ASSERT_EQ(example[string("second")].as_int(), result[string("second")].as_int()); + ASSERT_TRUE(result[string("third")].is_float()); + ASSERT_DOUBLE_EQ(example[string("third")].as_double(), result[string("third")].as_double()); +} + +TEST(yaml_test, test_yaml_map_recursive) { + mixed example, copy; + example[string("first")] = string("string"); + example[string("second")] = 13; + example[string("third")] = 3.1416; + for (auto it = example.begin(); it != example.end(); ++it) { + copy[it.get_key()] = it.get_value(); + } + example[string("self")] = copy; + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result[string("self")].is_array()); + ASSERT_FALSE(result[string("self")].as_array().is_pseudo_vector()); + ASSERT_TRUE(result[string("self")][string("first")].is_string()); + ASSERT_TRUE(example[string("self")][string("first")].as_string() == result[string("self")][string("first")].as_string()); + ASSERT_TRUE(result[string("self")][string("second")].is_int()); + ASSERT_EQ(example[string("self")][string("second")].as_int(), result[string("self")][string("second")].as_int()); + ASSERT_TRUE(result[string("self")][string("third")].is_float()); + ASSERT_DOUBLE_EQ(example[string("self")][string("third")].as_double(), result[string("self")][string("third")].as_double()); +} + +TEST(yaml_test, test_yaml_empty_array) { + array empty_array; + mixed result = f$yaml_parse(f$yaml_emit(empty_array)); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().empty()); +} + +TEST(yaml_test, test_yaml_null) { + mixed example; + mixed result = f$yaml_parse(f$yaml_emit(example)); + ASSERT_TRUE(result.is_null()); +} + +TEST(yaml_test, test_yaml_string_file) { + mixed example = string("string"); + string filename("test_yaml_string"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_string()); + ASSERT_TRUE(example.as_string() == result.as_string()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_empty_string_file) { + mixed example = string(""); + string filename("test_yaml_empty_string"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_string()); + ASSERT_TRUE(example.as_string() == result.as_string()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_int_file) { + mixed example = 13; + string filename("test_yaml_int"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_int()); + ASSERT_EQ(example.as_int(), result.as_int()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_float_file) { + mixed example = 3.1416; + string filename("test_yaml_float"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_float()); + ASSERT_DOUBLE_EQ(example.as_double(), result.as_double()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_int_as_string_file) { + mixed example = string("13"); + string filename("test_yaml_int_as_string"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_string()); + ASSERT_EQ(example.as_string(), result.as_string()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_float_as_string_file) { + mixed example = string("3.1416"); + string filename("test_yaml_float_as_string"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_string()); + ASSERT_EQ(example.as_string(), result.as_string()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_vector_file) { + mixed example; + example.push_back(string("string")); + example.push_back(13); + example.push_back(3.1416); + string filename("test_yaml_vector"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[0].is_string()); + ASSERT_TRUE(example[0].as_string() == result[0].as_string()); + ASSERT_TRUE(result[1].is_int()); + ASSERT_EQ(example[1].as_int(), result[1].as_int()); + ASSERT_TRUE(result[2].is_float()); + ASSERT_DOUBLE_EQ(example[2].as_double(), result[2].as_double()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_vector_recursive_file) { + mixed example, copy; + example.push_back(string("string")); + example.push_back(13); + example.push_back(3.1416); + for (auto it = example.begin(); it != example.end(); ++it) { + copy.push_back(it.get_value()); + } + example.push_back(copy); + string filename("test_yaml_vector_recursive"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result[3].is_array()); + ASSERT_TRUE(result[3].as_array().is_pseudo_vector()); + ASSERT_TRUE(result[3][0].is_string()); + ASSERT_TRUE(example[3][0].as_string() == result[3][0].as_string()); + ASSERT_TRUE(result[3][1].is_int()); + ASSERT_EQ(example[3][1].as_int(), result[3][1].as_int()); + ASSERT_TRUE(result[3][2].is_float()); + ASSERT_DOUBLE_EQ(example[3][2].as_double(), result[3][2].as_double()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_bool_file) { + mixed example; + example.push_back(true); + example.push_back(false); + example.push_back(string("true")); + example.push_back(string("false")); + string filename("test_yaml_bool"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[0].is_bool()); + ASSERT_TRUE(example[0].as_bool() == result[0].as_bool()); + ASSERT_TRUE(result[1].is_bool()); + ASSERT_TRUE(example[1].as_bool() == result[1].as_bool()); + ASSERT_TRUE(result[2].is_string()); + ASSERT_TRUE(example[2].as_string() == result[2].as_string()); + ASSERT_TRUE(result[3].is_string()); + ASSERT_TRUE(example[3].as_string() == result[3].as_string()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_map_file) { + mixed example; + example[string("first")] = string("string"); + example[string("second")] = 13; + example[string("third")] = 3.1416; + string filename("test_yaml_map"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_array()); + ASSERT_FALSE(result.as_array().is_pseudo_vector()); + ASSERT_TRUE(result[string("first")].is_string()); + ASSERT_TRUE(example[string("first")].as_string() == result[string("first")].as_string()); + ASSERT_TRUE(result[string("second")].is_int()); + ASSERT_EQ(example[string("second")].as_int(), result[string("second")].as_int()); + ASSERT_TRUE(result[string("third")].is_float()); + ASSERT_DOUBLE_EQ(example[string("third")].as_double(), result[string("third")].as_double()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_map_recursive_file) { + mixed example, copy; + example[string("first")] = string("string"); + example[string("second")] = 13; + example[string("third")] = 3.1416; + for (auto it = example.begin(); it != example.end(); ++it) { + copy[it.get_key()] = it.get_value(); + } + example[string("self")] = copy; + string filename("test_yaml_map_recursive"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result[string("self")].is_array()); + ASSERT_FALSE(result[string("self")].as_array().is_pseudo_vector()); + ASSERT_TRUE(result[string("self")][string("first")].is_string()); + ASSERT_TRUE(example[string("self")][string("first")].as_string() == result[string("self")][string("first")].as_string()); + ASSERT_TRUE(result[string("self")][string("second")].is_int()); + ASSERT_EQ(example[string("self")][string("second")].as_int(), result[string("self")][string("second")].as_int()); + ASSERT_TRUE(result[string("self")][string("third")].is_float()); + ASSERT_DOUBLE_EQ(example[string("self")][string("third")].as_double(), result[string("self")][string("third")].as_double()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_empty_array_file) { + array empty_array; + string filename("test_yaml_empty_array"); + ASSERT_TRUE(f$yaml_emit_file(filename, empty_array)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_array()); + ASSERT_TRUE(result.as_array().empty()); + ASSERT_TRUE(f$unlink(filename)); +} + +TEST(yaml_test, test_yaml_null_file) { + mixed example; + string filename("test_yaml_null"); + ASSERT_TRUE(f$yaml_emit_file(filename, example)); + mixed result = f$yaml_parse_file(filename); + ASSERT_TRUE(result.is_null()); + ASSERT_TRUE(f$unlink(filename)); +} diff --git a/tests/phpt/yaml/01_yaml_complex.php b/tests/phpt/yaml/01_yaml_complex.php new file mode 100644 index 0000000000..4481ff7d34 --- /dev/null +++ b/tests/phpt/yaml/01_yaml_complex.php @@ -0,0 +1,13 @@ +@ok +"true", true=>true, false=>false, array("false"=>"false", 10 => null))); + echo(serialize($in) . PHP_EOL); + /** @param mixed $out */ + $out = yaml_parse(yaml_emit($in)); + echo(serialize($out) . PHP_EOL); +} + +test_yaml_complex(); diff --git a/tests/phpt/yaml/02_yaml_config_file.php b/tests/phpt/yaml/02_yaml_config_file.php new file mode 100644 index 0000000000..30ee53c33b --- /dev/null +++ b/tests/phpt/yaml/02_yaml_config_file.php @@ -0,0 +1,15 @@ +@ok +