1// Copyright (c) 2014 Tomoki Imai
2// Copyright (c) 2023 Nikita Knizev
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#include <boost/spirit/include/support_line_pos_iterator.hpp>
8
9#include <boost/core/lightweight_test.hpp>
10#include <boost/type_traits/is_same.hpp>
11#include <boost/assign.hpp>
12#include <boost/static_assert.hpp>
13#include <iterator>
14#include <string>
15#include <vector>
16
17struct validation {
18 validation(size_t line, size_t column)
19 : line(line), column(column), inside_newline(true) {
20 }
21
22 validation(size_t line, size_t column, std::string current)
23 : line(line), column(column), current(current), inside_newline(false) {
24 }
25
26 size_t line;
27 size_t column;
28 std::string current;
29 bool inside_newline;
30};
31
32typedef std::vector<validation> validations;
33
34struct string_forward_iterator : public boost::iterator_adaptor<
35 string_forward_iterator // Derived
36 , std::string::const_iterator // Base
37 , boost::use_default // Value
38 , boost::forward_traversal_tag // CategoryOrTraversal
39 >
40{
41 explicit string_forward_iterator(std::string::const_iterator it)
42 : string_forward_iterator::iterator_adaptor_(it) {}
43};
44BOOST_STATIC_ASSERT(boost::is_same<std::iterator_traits<string_forward_iterator>::iterator_category, std::forward_iterator_tag>::value);
45
46template <typename Iterator>
47void test(Iterator first, Iterator last, validations const& validations, bool singlechar_newline) {
48 typedef boost::spirit::line_pos_iterator<Iterator> pos_iterator_t;
49
50 pos_iterator_t const input_begin(first);
51 pos_iterator_t const input_end(last);
52 pos_iterator_t position(input_begin);
53 validations::const_iterator expected = validations.begin();
54
55 for (; position != input_end && expected != validations.end(); ++position, ++expected) {
56 if (expected->inside_newline && singlechar_newline)
57 if (++expected == validations.end())
58 break;
59 boost::iterator_range<pos_iterator_t> const range = get_current_line(input_begin, position, input_end);
60 std::string const current(range.begin(), range.end());
61
62 BOOST_TEST_EQ(expected->line, get_line(position));
63 BOOST_TEST_EQ(expected->column, get_column(input_begin, position));
64 BOOST_TEST_EQ(expected->current, current);
65 }
66 if (expected != validations.end() && expected->inside_newline && singlechar_newline)
67 ++expected;
68
69 BOOST_TEST(position == input_end);
70 BOOST_TEST(expected == validations.end());
71}
72
73void test(std::string const& input, validations const& validations, bool singlechar_newline) {
74 test(first: input.begin(), last: input.end(), validations, singlechar_newline);
75 test(first: string_forward_iterator(input.begin()), last: string_forward_iterator(input.end()),
76 validations, singlechar_newline);
77}
78
79void test_only(std::string const& line_break) {
80 std::string const input = line_break + line_break + line_break;
81 validations const validations = boost::assign::list_of<validation>
82 (u: 1,us: 1,us: "")(2,1)
83 (2,1,"")(3,1)
84 (3,1,"")(4,1);
85 test(input, validations, singlechar_newline: line_break.size() == 1);
86}
87
88void test_in_text(std::string const& line_break) {
89 std::string const input = "foo" + line_break + "bar" + line_break + "git";
90 validations const validations = boost::assign::list_of<validation>
91 (u: 1,us: 1,us: "foo")(1,2,"foo")(1,3,"foo")(1,4,"foo")(2,1)
92 (2,1,"bar")(2,2,"bar")(2,3,"bar")(2,4,"bar")(3,1)
93 (3,1,"git")(3,2,"git")(3,3,"git");
94 test(input, validations, singlechar_newline: line_break.size() == 1);
95}
96
97void test_at_begin(std::string const& line_break) {
98 std::string const input = line_break + "bar" + line_break + "git";
99 validations const validations = boost::assign::list_of<validation>
100 (u: 1,us: 1,us: "")(2,1)
101 (2,1,"bar")(2,2,"bar")(2,3,"bar")(2,4,"bar")(3,1)
102 (3,1,"git")(3,2,"git")(3,3,"git");
103 test(input, validations, singlechar_newline: line_break.size() == 1);
104}
105
106void test_at_end(std::string const& line_break) {
107 std::string const input = "foo" + line_break + "bar" + line_break;
108 validations const validations = boost::assign::list_of<validation>
109 (u: 1,us: 1,us: "foo")(1,2,"foo")(1,3,"foo")(1,4,"foo")(2,1)
110 (2,1,"bar")(2,2,"bar")(2,3,"bar")(2,4,"bar")(3,1);
111 test(input, validations, singlechar_newline: line_break.size() == 1);
112}
113
114void test_mixed() {
115 std::string const input = "\n\n\r\r\n\r";
116 validations const validations = boost::assign::list_of<validation>
117 (u: 1,us: 1,us: "") // \n
118 (2,1,"")(3,1) // \n\r
119 (3,1,"")(4,1) // \r\n
120 (4,1,""); // \r
121 test(input, validations, singlechar_newline: false);
122}
123
124void test(std::string const& line_break)
125{
126 test_only(line_break);
127 test_in_text(line_break);
128 test_at_begin(line_break);
129 test_at_end(line_break);
130}
131
132int main()
133{
134 test(line_break: "\n");
135 test(line_break: "\r\n");
136 test(line_break: "\r");
137 test(line_break: "\n\r");
138 test_mixed();
139
140 return boost::report_errors();
141}
142

source code of boost/libs/spirit/test/support/line_pos_iterator.cpp