mirror of
				https://github.com/red0124/ssp.git
				synced 2025-11-04 14:46:45 +01:00 
			
		
		
		
	Fix handling of invalid conversion/split within parser, update parser tests
This commit is contained in:
		
							parent
							
								
									7c9ba953ad
								
							
						
					
					
						commit
						2e1c4c97ec
					
				@ -88,14 +88,26 @@ public:
 | 
				
			|||||||
        return to_object<T>(get_next<Ts...>());
 | 
					        return to_object<T>(get_next<Ts...>());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO make the method work with if valid() returns false
 | 
				
			||||||
    size_t line() const {
 | 
					    size_t line() const {
 | 
				
			||||||
        return valid() ? reader_.line_number_ - 1 : 0;
 | 
					        return valid() ? reader_.line_number_ - 1 : 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename T, typename... Ts>
 | 
					    template <typename T, typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<T, Ts...> get_next() {
 | 
					    no_void_validator_tup_t<T, Ts...> get_next() {
 | 
				
			||||||
 | 
					        std::optional<std::string> error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!eof_) {
 | 
					        if (!eof_) {
 | 
				
			||||||
            reader_.parse();
 | 
					            if constexpr (throw_on_error) {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    reader_.parse();
 | 
				
			||||||
 | 
					                } catch (...) {
 | 
				
			||||||
 | 
					                    read_line();
 | 
				
			||||||
 | 
					                    throw;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                reader_.parse();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        reader_.update();
 | 
					        reader_.update();
 | 
				
			||||||
@ -112,6 +124,17 @@ public:
 | 
				
			|||||||
            return {};
 | 
					            return {};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if constexpr (throw_on_error) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                auto value = reader_.converter_.template convert<T, Ts...>();
 | 
				
			||||||
 | 
					                read_line();
 | 
				
			||||||
 | 
					                return value;
 | 
				
			||||||
 | 
					            } catch (...) {
 | 
				
			||||||
 | 
					                read_line();
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto value = reader_.converter_.template convert<T, Ts...>();
 | 
					        auto value = reader_.converter_.template convert<T, Ts...>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!reader_.converter_.valid()) {
 | 
					        if (!reader_.converter_.valid()) {
 | 
				
			||||||
 | 
				
			|||||||
@ -162,7 +162,6 @@ private:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO handle this efficiently (if multiline is enabled)
 | 
					 | 
				
			||||||
    void handle_error_unterminated_quote() {
 | 
					    void handle_error_unterminated_quote() {
 | 
				
			||||||
        constexpr static auto error_msg = "unterminated quote";
 | 
					        constexpr static auto error_msg = "unterminated quote";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -772,7 +772,8 @@ static inline std::string no_escape(std::string& s) {
 | 
				
			|||||||
    return s;
 | 
					    return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE("parser test csv on multiple lines with escapes") {
 | 
					template <typename... Ts>
 | 
				
			||||||
 | 
					void test_escape_multiline() {
 | 
				
			||||||
    unique_file_name f{"test_parser"};
 | 
					    unique_file_name f{"test_parser"};
 | 
				
			||||||
    std::vector<X> data = {{1, 2, "x\\\nx\\\r\nx"},
 | 
					    std::vector<X> data = {{1, 2, "x\\\nx\\\r\nx"},
 | 
				
			||||||
                           {5, 6, "z\\\nz\\\nz"},
 | 
					                           {5, 6, "z\\\nz\\\nz"},
 | 
				
			||||||
@ -792,11 +793,11 @@ TEST_CASE("parser test csv on multiple lines with escapes") {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss::parser<ss::multiline, ss::escape<'\\'>> p{f.name, ","};
 | 
					    ss::parser<ss::multiline, ss::escape<'\\'>, Ts...> p{f.name, ","};
 | 
				
			||||||
    std::vector<X> i;
 | 
					    std::vector<X> i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (!p.eof()) {
 | 
					    while (!p.eof()) {
 | 
				
			||||||
        auto a = p.get_next<int, double, std::string>();
 | 
					        auto a = p.template get_next<int, double, std::string>();
 | 
				
			||||||
        i.emplace_back(ss::to_object<X>(a));
 | 
					        i.emplace_back(ss::to_object<X>(a));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -805,14 +806,24 @@ TEST_CASE("parser test csv on multiple lines with escapes") {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    CHECK_EQ(i, data);
 | 
					    CHECK_EQ(i, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss::parser<ss::escape<'\\'>> p_no_multiline{f.name, ","};
 | 
					    ss::parser<ss::escape<'\\'>, Ts...> p_no_multiline{f.name, ","};
 | 
				
			||||||
    while (!p.eof()) {
 | 
					    while (!p.eof()) {
 | 
				
			||||||
        auto a = p_no_multiline.get_next<int, double, std::string>();
 | 
					        auto command = [&] {
 | 
				
			||||||
        CHECK_FALSE(p.valid());
 | 
					            auto a =
 | 
				
			||||||
 | 
					                p_no_multiline.template get_next<int, double, std::string>();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        expect_error_on_command(p_no_multiline, command);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
 | 
					TEST_CASE("parser test csv on multiple lines with escapes") {
 | 
				
			||||||
 | 
					    test_escape_multiline();
 | 
				
			||||||
 | 
					    test_escape_multiline<ss::string_error>();
 | 
				
			||||||
 | 
					    test_escape_multiline<ss::throw_on_error>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename... Ts>
 | 
				
			||||||
 | 
					void test_quote_escape_multiline() {
 | 
				
			||||||
    unique_file_name f{"test_parser"};
 | 
					    unique_file_name f{"test_parser"};
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::ofstream out{f.name};
 | 
					        std::ofstream out{f.name};
 | 
				
			||||||
@ -827,17 +838,28 @@ TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
 | 
				
			|||||||
        out << "7,8,\"just strings\"" << std::endl;
 | 
					        out << "7,8,\"just strings\"" << std::endl;
 | 
				
			||||||
        out << "9,10,just strings" << std::endl;
 | 
					        out << "9,10,just strings" << std::endl;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    size_t bad_lines = 1;
 | 
				
			||||||
 | 
					    auto num_errors = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>> p{f.name};
 | 
					    ss::parser<ss::multiline, ss::escape<'\\'>, ss::quote<'"'>, Ts...> p{
 | 
				
			||||||
 | 
					        f.name};
 | 
				
			||||||
    std::vector<X> i;
 | 
					    std::vector<X> i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (!p.eof()) {
 | 
					    while (!p.eof()) {
 | 
				
			||||||
        auto a = p.get_next<int, double, std::string>();
 | 
					        try {
 | 
				
			||||||
        if (p.valid()) {
 | 
					            auto a = p.template get_next<int, double, std::string>();
 | 
				
			||||||
            i.emplace_back(ss::to_object<X>(a));
 | 
					            if (p.valid()) {
 | 
				
			||||||
 | 
					                i.emplace_back(ss::to_object<X>(a));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ++num_errors;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (const std::exception& e) {
 | 
				
			||||||
 | 
					            ++num_errors;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CHECK(bad_lines == num_errors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<X> data = {{1, 2, "just\n\nstrings"},
 | 
					    std::vector<X> data = {{1, 2, "just\n\nstrings"},
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
                           {3, 4, "just\r\nsome\r\n\n\nstrings"},
 | 
					                           {3, 4, "just\r\nsome\r\n\n\nstrings"},
 | 
				
			||||||
@ -852,7 +874,14 @@ TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
 | 
				
			|||||||
    CHECK_EQ(i, data);
 | 
					    CHECK_EQ(i, data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE("parser test multiline restricted") {
 | 
					TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
 | 
				
			||||||
 | 
					    test_quote_escape_multiline();
 | 
				
			||||||
 | 
					    test_quote_escape_multiline<ss::string_error>();
 | 
				
			||||||
 | 
					    test_quote_escape_multiline<ss::throw_on_error>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename... Ts>
 | 
				
			||||||
 | 
					void test_multiline_restricted() {
 | 
				
			||||||
    unique_file_name f{"test_parser"};
 | 
					    unique_file_name f{"test_parser"};
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::ofstream out{f.name};
 | 
					        std::ofstream out{f.name};
 | 
				
			||||||
@ -871,18 +900,29 @@ TEST_CASE("parser test multiline restricted") {
 | 
				
			|||||||
        out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
 | 
					        out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
 | 
				
			||||||
        out << "19,20,just strings" << std::endl;
 | 
					        out << "19,20,just strings" << std::endl;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    auto bad_lines = 15;
 | 
				
			||||||
 | 
					    auto num_errors = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>>
 | 
					    ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>,
 | 
				
			||||||
 | 
					               Ts...>
 | 
				
			||||||
        p{f.name, ","};
 | 
					        p{f.name, ","};
 | 
				
			||||||
    std::vector<X> i;
 | 
					    std::vector<X> i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (!p.eof()) {
 | 
					    while (!p.eof()) {
 | 
				
			||||||
        auto a = p.get_next<int, double, std::string>();
 | 
					        try {
 | 
				
			||||||
        if (p.valid()) {
 | 
					            auto a = p.template get_next<int, double, std::string>();
 | 
				
			||||||
            i.emplace_back(ss::to_object<X>(a));
 | 
					            if (p.valid()) {
 | 
				
			||||||
 | 
					                i.emplace_back(ss::to_object<X>(a));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ++num_errors;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (const std::exception& e) {
 | 
				
			||||||
 | 
					            ++num_errors;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CHECK(bad_lines == num_errors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<X> data = {{1, 2, "just\n\nstrings"},
 | 
					    std::vector<X> data = {{1, 2, "just\n\nstrings"},
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
                           {5, 6, "just\n\r\nstrings"},
 | 
					                           {5, 6, "just\n\r\nstrings"},
 | 
				
			||||||
@ -896,9 +936,19 @@ TEST_CASE("parser test multiline restricted") {
 | 
				
			|||||||
        update_if_crlf(s);
 | 
					        update_if_crlf(s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (i.size() != data.size()) {
 | 
				
			||||||
 | 
					        CHECK_EQ(i.size(), data.size());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CHECK_EQ(i, data);
 | 
					    CHECK_EQ(i, data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("parser test multiline restricted") {
 | 
				
			||||||
 | 
					    test_multiline_restricted();
 | 
				
			||||||
 | 
					    test_multiline_restricted<ss::string_error>();
 | 
				
			||||||
 | 
					    test_multiline_restricted<ss::throw_on_error>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
void test_unterminated_line_impl(const std::vector<std::string>& lines,
 | 
					void test_unterminated_line_impl(const std::vector<std::string>& lines,
 | 
				
			||||||
                                 size_t bad_line) {
 | 
					                                 size_t bad_line) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user