1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6  */
7 
8 #include "orcus_test_global.hpp"
9 #include "orcus/spreadsheet/document.hpp"
10 #include "orcus/spreadsheet/sheet.hpp"
11 #include "orcus/pstring.hpp"
12 #include "orcus/stream.hpp"
13 
14 #include <sstream>
15 #include <cmath>
16 #include <iostream>
17 #include <chrono>
18 
19 namespace orcus { namespace test {
20 
stack_printer(const char * msg)21 stack_printer::stack_printer(const char* msg) :
22     m_msg(msg)
23 {
24     std::cerr << m_msg << ": --begin" << std::endl;
25     m_start_time = get_time();
26 }
27 
~stack_printer()28 stack_printer::~stack_printer()
29 {
30     double end_time = get_time();
31     std::cerr << m_msg << ": --end (duration: " << (end_time-m_start_time) << " sec)" << std::endl;
32 }
33 
get_time() const34 double stack_printer::get_time() const
35 {
36     double v = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
37     return v / 1000.0;
38 }
39 
assert_error(const char * filename,size_t line_no,const char * msg)40 assert_error::assert_error(const char* filename, size_t line_no, const char* msg)
41 {
42     std::ostringstream os;
43     os << filename << ":" << line_no << ": " << msg;
44     m_msg = os.str();
45 }
46 
what() const47 const char* assert_error::what() const noexcept
48 {
49     return m_msg.data();
50 }
51 
get_content_check(const spreadsheet::document & doc)52 std::string get_content_check(const spreadsheet::document& doc)
53 {
54     std::ostringstream os;
55     doc.dump_check(os);
56     return os.str();
57 }
58 
get_content_as_csv(const spreadsheet::document & doc,spreadsheet::sheet_t sheet_index)59 std::string get_content_as_csv(const spreadsheet::document& doc, spreadsheet::sheet_t sheet_index)
60 {
61     const spreadsheet::sheet* sh = doc.get_sheet(sheet_index);
62     if (!sh)
63         return std::string();
64 
65     std::ostringstream os;
66     sh->dump_csv(os);
67     return os.str();
68 }
69 
verify_content(const char * filename,size_t line_no,const pstring & expected,const std::string & actual)70 void verify_content(
71     const char* filename, size_t line_no, const pstring& expected, const std::string& actual)
72 {
73     pstring s1 = expected;
74     pstring s2(actual.data(), actual.size());
75     s1 = s1.trim();
76     s2 = s2.trim();
77 
78     if (s1 != s2)
79     {
80         // TODO : improve the error message to make it more viewer-friendly.
81 
82         size_t diff_pos = locate_first_different_char(s1, s2);
83         std::string msg_s1 = create_parse_error_output(s1, diff_pos);
84         std::string msg_s2 = create_parse_error_output(s2, diff_pos);
85 
86         std::ostringstream os;
87         os << "content is not as expected: " << std::endl << std::endl
88             << "* expected:" << std::endl << std::endl
89             << msg_s1 << std::endl
90             << "* actual:" << std::endl << std::endl
91             << msg_s2;
92 
93         throw assert_error(filename, line_no, os.str().data());
94     }
95 }
96 
verify_content(const char * filename,size_t line_no,const spreadsheet::document & doc,const pstring & expected)97 void verify_content(
98     const char* filename, size_t line_no, const spreadsheet::document& doc, const pstring& expected)
99 {
100     std::string actual = get_content_check(doc);
101     verify_content(filename, line_no, expected, actual);
102 }
103 
verify_value_to_decimals(const char * filename,size_t line_no,double expected,double actual,int decimals)104 void verify_value_to_decimals(
105     const char* filename, size_t line_no, double expected, double actual, int decimals)
106 {
107     for (int i = 0; i < decimals; ++i)
108     {
109         expected *= 10.0;
110         actual *= 10.0;
111     }
112 
113     long expected_i = std::lround(expected);
114     long actual_i = std::lround(actual);
115 
116     if (expected_i == actual_i)
117         return;
118 
119     expected = expected_i;
120     actual = actual_i;
121 
122     for (int i = 0; i < decimals; ++i)
123     {
124         expected /= 10.0;
125         actual /= 10.0;
126     }
127 
128     std::ostringstream os;
129     os << "value is not as expected: (expected: " << expected << "; actual: " << actual << ")";
130     throw assert_error(filename, line_no, os.str().data());
131 }
132 
prefix_multiline_string(const pstring & str,const pstring & prefix)133 std::string prefix_multiline_string(const pstring& str, const pstring& prefix)
134 {
135     std::ostringstream os;
136 
137     const char* p = str.data();
138     const char* p_end = p + str.size();
139 
140     const char* p0 = nullptr;
141     for (; p != p_end; ++p)
142     {
143         if (!p0)
144             p0 = p;
145 
146         if (*p == '\n')
147         {
148             os << prefix << pstring(p0, std::distance(p0, p)) << '\n';
149             p0 = nullptr;
150         }
151     }
152 
153     if (p0)
154         os << prefix << pstring(p0, std::distance(p0, p));
155 
156     return os.str();
157 }
158 
159 }}
160 
161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
162