diff options
34 files changed, 1865 insertions, 78 deletions
diff --git a/.gitmodules b/.gitmodules index ff480831..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "lib/utfcpp"] - path = lib/utfcpp - url = http://github.com/ledger/utfcpp.git diff --git a/.travis.yml b/.travis.yml index 06ead752..98b0ab82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,8 @@ env: - BOOST_LIBS="date_time,filesystem,iostreams,python,regex,system,test" # List of required Homebrew formulae to install - BREWS="gmp,mpfr" + # Encrypted COVERITY_SCAN_TOKEN + - secure: "mYNxD1B8WNSvUeKzInehZ7syi2g1jH2ymeSQxoeKKD2duq3pvNWPdZdc4o9MlWQcAqcz58rhFZRIpuEWCnP0LbbJaG+MyuemMn9uAmg9Y4gFpMsBPHuTdf8pO3rDex+tkrr9puEJFgL+QV/TehxO6NDDpx7UdYvJb+4aZD/auYI=" matrix: exclude: @@ -47,6 +49,13 @@ matrix: # bool boost::regex_search<char const*, char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >(char const*, char const*, boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags) in global.cc.o addons: + coverity_scan: + project: + name: "ledger/ledger" + description: "Build submitted via Travis CI" + build_command_prepend: "cmake . -DUSE_PYTHON=ON -DBUILD_DEBUG=ON -DCLANG_GCOV=ON" + build_command: "make" + branch_pattern: coverity apt: sources: - ubuntu-toolchain-r-test @@ -84,7 +93,7 @@ before_script: - make script: - - make test + - ctest --output-on-failure - PYTHONPATH=. python python/demo.py after_script: diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c8c36ef..e455ec02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,9 @@ set(Ledger_VERSION_PATCH 1) set(Ledger_VERSION_PRERELEASE "-alpha.1") set(Ledger_VERSION_DATE 20141005) +# Point CMake at any custom modules we may ship +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + enable_testing() add_definitions(-std=c++11) @@ -244,13 +247,20 @@ endmacro(add_ledger_library_dependencies _target) ######################################################################## +include(FindUtfcpp) +if (UTFCPP_FOUND) + include_directories("${UTFCPP_INCLUDE_DIR}") +else() + message(FATAL_ERROR "Missing required header file: utf8.h\n" + "Define UTFCPP_PATH or install utfcpp locally into the source tree below lib/utfcpp/." + ) +endif() + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) # add the binary tree to the search path for include files so that we will -# find TutorialConfig.h -include_directories("${PROJECT_SOURCE_DIR}/lib") -include_directories("${PROJECT_SOURCE_DIR}/lib/utfcpp/source") +# find system.hh include_directories("${PROJECT_BINARY_DIR}") configure_file( @@ -490,17 +490,10 @@ class PrepareBuild(CommandLineApp): # Update local files with the latest information # ######################################################################### - def phase_submodule(self, *args): - self.log.info('Executing phase: submodule') - if self.git_working_tree(): - self.execute('git', 'submodule', 'init') - self.execute('git', 'submodule', 'update') - def phase_pull(self, *args): self.log.info('Executing phase: pull') if self.git_working_tree(): self.execute('git', 'pull') - self.phase_submodule() ######################################################################### # Automatic installation of build dependencies # @@ -569,6 +562,7 @@ class PrepareBuild(CommandLineApp): 'libedit-dev', 'texinfo', 'lcov', + 'libutfcpp-dev', 'sloccount' ] + BoostInfo().dependencies('ubuntu-trusty') elif re.search('saucy', info): @@ -606,6 +600,7 @@ class PrepareBuild(CommandLineApp): 'libedit-dev', 'texinfo', 'lcov', + 'libutfcpp-dev', 'sloccount' ] + BoostInfo().dependencies('ubuntu-precise') else: @@ -885,7 +880,6 @@ class PrepareBuild(CommandLineApp): def phase_config(self, *args): self.log.info('Executing phase: config') - self.phase_submodule() self.phase_configure(*args) if self.should_clean: self.phase_clean() diff --git a/cmake/FindUtfcpp.cmake b/cmake/FindUtfcpp.cmake new file mode 100644 index 00000000..185a8d88 --- /dev/null +++ b/cmake/FindUtfcpp.cmake @@ -0,0 +1,30 @@ +# - Try to find utfcpp +# Once done, this will define +# +# UTFCPP_FOUND - system has utfcpp's utf8.h +# UTFCPP_PATH - the utfcpp include directories + +include(CheckCXXSourceCompiles) + +set(UTFCPP_FOUND FALSE) + +find_path(UTFCPP_INCLUDE_DIR + NAMES utf8.h + HINTS "${UTFCPP_PATH}" "${PROJECT_SOURCE_DIR}/lib/utfcpp/v2_0/source" +) + +if (UTFCPP_INCLUDE_DIR) + set(CMAKE_REQUIRED_INCLUDES "${UTFCPP_INCLUDE_DIR}") + set(UTFCPP_FOUND TRUE) +endif() + +check_cxx_source_compiles(" +#include <string> +#include \"utf8.h\" + +int main(int argc, char** argv) { + std::string input = std::string(\"utfcpp\"); + const char * p = input.c_str(); + std::size_t len = input.length(); + utf8::is_valid(p, p + len); +}" HAVE_WORKING_UTFCPP) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 72c1165d..14a71778 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -7914,6 +7914,13 @@ considering children. The cost of a posting; the cost of an account, without its children. +@item v +The market value of a posting or an account, without its children. + +@item g +The net gain (market value minus cost basis), for a posting or an +account, without its children. It is the same as @samp{v-b}. + @item l The depth (``level'') of an account. If an account has one parent, its depth is one. @@ -8153,7 +8160,7 @@ Render the given @var{expression} as a string, applying the proper ANSI escape codes to display it in the given @var{color} if @var{bool} is true. It typically checks the value of the option @option{--color}. Since ANSI escape codes include non-printable character sequences, such as escape @kbd{^[} -the following example may not appear as the final result on the commandline. +the following example may not appear as the final result on the command-line. @smallexample @c command:4D836EE,with_input:3406FC1 $ ledger -f expr.dat --format "%(ansify_if(account, blue, options.color))\n" reg @end smallexample diff --git a/lib/utfcpp b/lib/utfcpp deleted file mode 160000 -Subproject 2233ec933f5661c7050b94d3b14f5f9f51ae3d5 diff --git a/doc/LICENSE-utfcpp b/lib/utfcpp/v2_0/LICENSE index 1751a003..36b7cd93 100644 --- a/doc/LICENSE-utfcpp +++ b/lib/utfcpp/v2_0/LICENSE @@ -1,4 +1,4 @@ -Copyright 2006 Nemanja Trifunovic +Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by diff --git a/lib/utfcpp/v2_0/buildrelease.pl b/lib/utfcpp/v2_0/buildrelease.pl new file mode 100755 index 00000000..ed3a17bb --- /dev/null +++ b/lib/utfcpp/v2_0/buildrelease.pl @@ -0,0 +1,18 @@ +#! /usr/bin/perl + +$release_files = 'source/utf8.h source/utf8/core.h source/utf8/checked.h source/utf8/unchecked.h doc/utf8cpp.html doc/ReleaseNotes'; + +# First get the latest version +`svn update`; + +# Then construct the name of the zip file +$argc = @ARGV; +if ($argc > 0) { + $zip_name = $ARGV[0]; +} +else { + $zip_name = "utf8"; +} + +# Zip the files to an archive +`zip $zip_name $release_files`; diff --git a/lib/utfcpp/v2_0/samples/Makefile b/lib/utfcpp/v2_0/samples/Makefile new file mode 100644 index 00000000..6cdd3c85 --- /dev/null +++ b/lib/utfcpp/v2_0/samples/Makefile @@ -0,0 +1,5 @@ +CC = g++ +CFLAGS = -g -Wall -pedantic + +docsample: docsample.cpp ../source/utf8.h + $(CC) $(CFLAGS) docsample.cpp -odocsample diff --git a/lib/utfcpp/v2_0/samples/docsample.cpp b/lib/utfcpp/v2_0/samples/docsample.cpp new file mode 100644 index 00000000..6f8953b9 --- /dev/null +++ b/lib/utfcpp/v2_0/samples/docsample.cpp @@ -0,0 +1,52 @@ +#include "../source/utf8.h" +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + + +using namespace std; + +int main(int argc, char** argv) +{ + if (argc != 2) { + cout << "\nUsage: docsample filename\n"; + return 0; + } + const char* test_file_path = argv[1]; + // Open the test file (must be UTF-8 encoded) + ifstream fs8(test_file_path); + if (!fs8.is_open()) { + cout << "Could not open " << test_file_path << endl; + return 0; + } + + unsigned line_count = 1; + string line; + // Play with all the lines in the file + while (getline(fs8, line)) { + // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function) + string::iterator end_it = utf8::find_invalid(line.begin(), line.end()); + if (end_it != line.end()) { + cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n"; + cout << "This part is fine: " << string(line.begin(), end_it) << "\n"; + } + // Get the line length (at least for the valid part) + int length = utf8::distance(line.begin(), end_it); + cout << "Length of line " << line_count << " is " << length << "\n"; + + // Convert it to utf-16 + vector<unsigned short> utf16line; + utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line)); + // And back to utf-8; + string utf8line; + utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line)); + // Confirm that the conversion went OK: + if (utf8line != string(line.begin(), end_it)) + cout << "Error in UTF-16 conversion at line: " << line_count << "\n"; + + line_count++; + } + + return 0; +} diff --git a/lib/utfcpp/v2_0/source/utf8.h b/lib/utfcpp/v2_0/source/utf8.h new file mode 100644 index 00000000..4e445140 --- /dev/null +++ b/lib/utfcpp/v2_0/source/utf8.h @@ -0,0 +1,34 @@ +// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard
diff --git a/lib/utfcpp/v2_0/source/utf8/checked.h b/lib/utfcpp/v2_0/source/utf8/checked.h new file mode 100644 index 00000000..13311551 --- /dev/null +++ b/lib/utfcpp/v2_0/source/utf8/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include <stdexcept> + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public ::std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template <typename octet_iterator> + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast<uint8_t>(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0); + *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0); + *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + return result; + } + + template <typename octet_iterator, typename output_iterator> + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = utf8::internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + out = utf8::append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + out = utf8::append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (start != end && utf8::internal::is_trail(*start)) + ++start; + break; + } + } + return out; + } + + template <typename octet_iterator, typename output_iterator> + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); + return utf8::replace_invalid(start, end, out, replacement_marker); + } + + template <typename octet_iterator> + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template <typename octet_iterator> + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return utf8::next(it, end); + } + + template <typename octet_iterator> + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (utf8::internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return utf8::peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template <typename octet_iterator> + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (utf8::internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return utf8::next(temp, end); + } + + template <typename octet_iterator, typename distance_type> + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + utf8::next(it, end); + } + + template <typename octet_iterator> + typename std::iterator_traits<octet_iterator>::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits<octet_iterator>::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::next(first, last); + return dist; + } + + template <typename u16bit_iterator, typename octet_iterator> + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + if (utf8::internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast<uint16_t>(trail_surrogate)); + } + else + throw invalid_utf16(static_cast<uint16_t>(cp)); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast<uint16_t>(cp)); + + result = utf8::append(cp, result); + } + return result; + } + + template <typename u16bit_iterator, typename octet_iterator> + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = utf8::next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast<uint16_t>(cp); + } + return result; + } + + template <typename octet_iterator, typename u32bit_iterator> + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::append(*(start++), result); + + return result; + } + + template <typename octet_iterator, typename u32bit_iterator> + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = utf8::next(start, end); + + return result; + } + + // The iterator class + template <typename octet_iterator> + class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + utf8::next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + utf8::next(it, range_end); + return temp; + } + iterator& operator -- () + { + utf8::prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/lib/utfcpp/v2_0/source/utf8/core.h b/lib/utfcpp/v2_0/source/utf8/core.h new file mode 100644 index 00000000..693d388c --- /dev/null +++ b/lib/utfcpp/v2_0/source/utf8/core.h @@ -0,0 +1,329 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include <iterator> + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template<typename octet_type> + inline uint8_t mask8(octet_type oc) + { + return static_cast<uint8_t>(0xff & oc); + } + template<typename u16_type> + inline uint16_t mask16(u16_type oc) + { + return static_cast<uint16_t>(0xffff & oc); + } + template<typename octet_type> + inline bool is_trail(octet_type oc) + { + return ((utf8::internal::mask8(oc) >> 6) == 0x2); + } + + template <typename u16> + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template <typename u16> + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template <typename u16> + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template <typename u32> + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } + + template <typename octet_iterator> + inline typename std::iterator_traits<octet_iterator>::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = utf8::internal::mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template <typename octet_difference_type> + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// Helper for get_sequence_x + template <typename octet_iterator> + utf_error increase_safely(octet_iterator& it, octet_iterator end) + { + if (++it == end) + return NOT_ENOUGH_ROOM; + + if (!utf8::internal::is_trail(*it)) + return INCOMPLETE_SEQUENCE; + + return UTF8_OK; + } + + #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} + + /// get_sequence_x functions decode utf-8 sequences of the length x + template <typename octet_iterator> + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + return UTF8_OK; + } + + template <typename octet_iterator> + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); + + return UTF8_OK; + } + + template <typename octet_iterator> + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + template <typename octet_iterator> + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR + + template <typename octet_iterator> + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type; + const octet_difference_type length = utf8::internal::sequence_length(it); + + // Get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 0: + return INVALID_LEAD; + case 1: + err = utf8::internal::get_sequence_1(it, end, cp); + break; + case 2: + err = utf8::internal::get_sequence_2(it, end, cp); + break; + case 3: + err = utf8::internal::get_sequence_3(it, end, cp); + break; + case 4: + err = utf8::internal::get_sequence_4(it, end, cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (utf8::internal::is_code_point_valid(cp)) { + if (!utf8::internal::is_overlong_sequence(cp, length)){ + // Passed! Return here. + code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template <typename octet_iterator> + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + uint32_t ignored; + return utf8::internal::validate_next(it, end, ignored); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template <typename octet_iterator> + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template <typename octet_iterator> + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (utf8::find_invalid(start, end) == end); + } + + template <typename octet_iterator> + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && + ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && + ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template <typename octet_iterator> + inline bool is_bom (octet_iterator it) + { + return ( + (utf8::internal::mask8(*it++)) == bom[0] && + (utf8::internal::mask8(*it++)) == bom[1] && + (utf8::internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/lib/utfcpp/v2_0/source/utf8/unchecked.h b/lib/utfcpp/v2_0/source/utf8/unchecked.h new file mode 100644 index 00000000..cb242716 --- /dev/null +++ b/lib/utfcpp/v2_0/source/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template <typename octet_iterator> + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast<uint8_t>(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0); + *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0); + *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); + } + return result; + } + + template <typename octet_iterator> + uint32_t next(octet_iterator& it) + { + uint32_t cp = utf8::internal::mask8(*it); + typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (utf8::internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template <typename octet_iterator> + uint32_t peek_next(octet_iterator it) + { + return utf8::unchecked::next(it); + } + + template <typename octet_iterator> + uint32_t prior(octet_iterator& it) + { + while (utf8::internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template <typename octet_iterator> + inline uint32_t previous(octet_iterator& it) + { + return utf8::unchecked::prior(it); + } + + template <typename octet_iterator, typename distance_type> + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + utf8::unchecked::next(it); + } + + template <typename octet_iterator> + typename std::iterator_traits<octet_iterator>::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits<octet_iterator>::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::unchecked::next(first); + return dist; + } + + template <typename u16bit_iterator, typename octet_iterator> + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = utf8::unchecked::append(cp, result); + } + return result; + } + + template <typename u16bit_iterator, typename octet_iterator> + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = utf8::unchecked::next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast<uint16_t>(cp); + } + return result; + } + + template <typename octet_iterator, typename u32bit_iterator> + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::unchecked::append(*(start++), result); + + return result; + } + + template <typename octet_iterator, typename u32bit_iterator> + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = utf8::unchecked::next(start); + + return result; + } + + // The iterator class + template <typename octet_iterator> + class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { + octet_iterator it; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + ::std::advance(it, utf8::internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + ::std::advance(it, utf8::internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + utf8::unchecked::prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::unchecked::prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ed6e51a..65e58edb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -152,7 +152,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") -Wno-unused-parameter -Wno-c++98-compat -fno-limit-debug-info) - + macro(ADD_PCH_RULE _header_filename _src_list _other_srcs) set(_pch_filename "${_header_filename}.pch") @@ -188,7 +188,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} DEPENDS ${_header_filename}) endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs) - + elseif(CMAKE_CXX_COMPILER MATCHES "g\\+\\+") set(GXX_WARNING_FLAGS -pedantic @@ -210,7 +210,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") -Wno-strict-aliasing) add_definitions(${GXX_WARNING_FLAGS}) - + macro(ADD_PCH_RULE _header_filename _src_list _other_srcs) set(_gch_filename "${_header_filename}.gch") @@ -247,7 +247,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} DEPENDS ${_header_filename}) endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs) - + else() macro(ADD_PCH_RULE _header_filename _src_list _other_srcs) endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs) diff --git a/src/emacs.h b/src/emacs.h index fef7a882..b89ce9f4 100644 --- a/src/emacs.h +++ b/src/emacs.h @@ -72,7 +72,7 @@ public: out.flush(); } virtual void operator()(post_t& post); - virtual string escape_string(string raw); + virtual string escape_string(string raw); }; } // namespace ledger diff --git a/src/history.cc b/src/history.cc index e3c459f3..8772d18c 100644 --- a/src/history.cc +++ b/src/history.cc @@ -475,7 +475,7 @@ commodity_history_impl_t::find_price(const commodity_t& source, #endif vertex_descriptor v = tv; - for (vertex_descriptor u = predecessorMap[v]; + for (vertex_descriptor u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) { @@ -78,8 +78,8 @@ public: commodity_t * default_commodity; bool keep_base; // --base - optional<path> price_db; // --price-db= - long quote_leeway; // --leeway= + optional<path> price_db; // --price-db= + long quote_leeway; // --leeway= bool get_quotes; // --download function<optional<price_point_t> diff --git a/src/pyinterp.h b/src/pyinterp.h index 32becbf6..fe86573a 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -77,7 +77,7 @@ public: if (name != "__main__") main_module->define_global(name, mod->module_object); return mod; - } + } python_interpreter_t() : session_t(), is_initialized(false) { TRACE_CTOR(python_interpreter_t, ""); diff --git a/src/select.cc b/src/select.cc index 81800f16..1141df04 100644 --- a/src/select.cc +++ b/src/select.cc @@ -396,7 +396,7 @@ value_t select_command(call_scope_t& args) #if 0 query_t query; keep_details_t keeper(true, true, true); - expr_t::ptr_op_t expr = + expr_t::ptr_op_t expr = query.parse_args(string_value(arg).to_sequence(), keeper, false, true); report.HANDLER(limit_).on("#select", query.get_query(query_t::QUERY_LIMIT)); #else diff --git a/src/strptime.cc b/src/strptime.cc index b64af96b..b31954f4 100644 --- a/src/strptime.cc +++ b/src/strptime.cc @@ -85,7 +85,7 @@ static char* _strptime(const char *s, const char *format, struct tm *tm) { if (tm->tm_wday == -1) return NULL; s += len; break; - + // month name. case 'b': case 'B': diff --git a/src/value.cc b/src/value.cc index 2737add9..4ea7c7a8 100644 --- a/src/value.cc +++ b/src/value.cc @@ -341,6 +341,10 @@ value_t& value_t::operator+=(const value_t& val) } switch (type()) { + case VOID: + *this = value_t(val); + return *this; + case DATETIME: switch (val.type()) { case INTEGER: diff --git a/src/value.h b/src/value.h index 810d34f9..c9084e03 100644 --- a/src/value.h +++ b/src/value.h @@ -435,7 +435,7 @@ public: return temp; } void in_place_roundto(int places); - + value_t truncated() const { value_t temp(*this); temp.in_place_truncate(); diff --git a/src/views.h b/src/views.h index 2be3d978..603b28da 100644 --- a/src/views.h +++ b/src/views.h @@ -235,7 +235,7 @@ public: optional<string> note() const { return ptr()->note; } - + bool has_tag(const string& tag) const { return ptr()->has_tag(tag); } diff --git a/src/wcwidth.cc b/src/wcwidth.cc index c23f83d7..75cd76be 100644 --- a/src/wcwidth.cc +++ b/src/wcwidth.cc @@ -195,7 +195,7 @@ int mk_wcwidth(boost::uint32_t ucs) /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + + return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || diff --git a/test/CheckBaselineTests.py b/test/CheckBaselineTests.py index f0eb2646..8659d1b5 100755 --- a/test/CheckBaselineTests.py +++ b/test/CheckBaselineTests.py @@ -23,7 +23,6 @@ class CheckBaselineTests (CheckOptions): 'args-only', 'debug', 'download', - 'file', 'force-color', 'force-pager', 'generated', @@ -33,6 +32,7 @@ class CheckBaselineTests (CheckOptions): 'no-pager', 'options', 'price-exp', + 'revalued-total', 'seed', 'trace', 'verbose', diff --git a/test/baseline/cmd-convert.test.disable b/test/baseline/cmd-convert.test index d444da52..8ee5bb2e 100644 --- a/test/baseline/cmd-convert.test.disable +++ b/test/baseline/cmd-convert.test @@ -17,7 +17,7 @@ end test test -f /dev/null --input-date-format "%m/%d/%Y" convert test/baseline/cmd-convert3.dat -> 1 __ERROR__ -While parsing file "$sourcepath/test/baseline/cmd-convert3.dat", line 1: +While parsing file "$sourcepath/test/baseline/cmd-convert3.dat", line 1: While parsing CSV line: 01/01/2011,, @@ -26,7 +26,7 @@ end test test -f /dev/null convert test/baseline/cmd-convert4.dat -> 1 __ERROR__ -While parsing file "$sourcepath/test/baseline/cmd-convert4.dat", line 1: +While parsing file "$sourcepath/test/baseline/cmd-convert4.dat", line 1: While parsing CSV line: bogus,$10, diff --git a/test/baseline/opt-file.test.disable b/test/baseline/opt-file.test index 66d0ab1b..66d0ab1b 100644 --- a/test/baseline/opt-file.test.disable +++ b/test/baseline/opt-file.test diff --git a/test/regress/1057.test b/test/regress/1057.test new file mode 100644 index 00000000..94d82767 --- /dev/null +++ b/test/regress/1057.test @@ -0,0 +1,11 @@ +2014/04/03 www.amazon.fr + Dépense:Loisir:Ordi:Matériel 101,50 € ; disque dur portable 2,5" 2000 Go + Dépense:Maison:Service:Poste + * Passif:Crédit:BanqueAccord -171,63 € + +test -f test/regress/1057.test --now=2014/06/27 emacs +(("$sourcepath/test/regress/1057.test" 1 (21308 34912 0) nil "www.amazon.fr" + (2 "Dépense:Loisir:Ordi:Matériel" "101,50 €" nil " disque dur portable 2,5\" 2000 Go") + (3 "Dépense:Maison:Service:Poste" "70,13 €" nil) + (4 "Passif:Crédit:BanqueAccord" "-171,63 €" t))) +end test diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test new file mode 100644 index 00000000..cfc0eabd --- /dev/null +++ b/test/regress/25A099C9.test @@ -0,0 +1,61 @@ +test -f test/garbage-input.dat reg -> 29 +__ERROR__ +While parsing file "$sourcepath/test/garbage-input.dat", line 1: +Error: Directive '/*' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 32: +Error: Directive '/**' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 36: +Error: Directive '/**' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 66: +Error: No quantity specified for amount +While parsing file "$sourcepath/test/garbage-input.dat", line 69: +Error: Unexpected whitespace at beginning of line +While parsing file "$sourcepath/test/garbage-input.dat", line 78: +Error: Directive '};' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 82: +Error: Directive '/**' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 93: +Error: Unexpected whitespace at beginning of line +While parsing file "$sourcepath/test/garbage-input.dat", line 97: +Error: Directive '{' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 98: +Error: Directive 'public:' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 120: +Error: Directive 'protected:' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 131: +Error: Directive 'public:' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 711: +Error: Unexpected whitespace at beginning of line +While parsing file "$sourcepath/test/garbage-input.dat", line 740: +Error: Directive 'private:' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 749: +Error: Unexpected whitespace at beginning of line +While parsing file "$sourcepath/test/garbage-input.dat", line 750: +Error: Directive '};' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 752: +Error: Invalid date/time: line amount_t amoun +While parsing file "$sourcepath/test/garbage-input.dat", line 756: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 758: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/test/garbage-input.dat", line 762: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 764: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/test/garbage-input.dat", line 768: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 770: +Error: Invalid date/time: line string amount_ +While parsing file "$sourcepath/test/garbage-input.dat", line 774: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 776: +Error: Invalid date/time: line std::ostream& +While parsing file "$sourcepath/test/garbage-input.dat", line 782: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 783: +Error: Invalid date/time: line std::istream& +While parsing file "$sourcepath/test/garbage-input.dat", line 786: +Error: Directive '}' requires an argument +While parsing file "$sourcepath/test/garbage-input.dat", line 789: +Error: Unexpected whitespace at beginning of line +end test diff --git a/test/regress/25A099C9.test.disable b/test/regress/25A099C9.test.disable deleted file mode 100644 index e511c799..00000000 --- a/test/regress/25A099C9.test.disable +++ /dev/null @@ -1,43 +0,0 @@ -test -f test/garbage-input.dat reg -> 20 -__ERROR__ -While parsing file "$sourcepath/test/garbage-input.dat", line 2: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 33: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 37: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 66: -Error: No quantity specified for amount -While parsing file "$sourcepath/test/garbage-input.dat", line 69: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 83: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 93: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 99: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 121: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 132: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 711: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 741: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 749: -Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 752: -Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/test/garbage-input.dat", line 758: -Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 764: -Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 770: -Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 776: -Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/test/garbage-input.dat", line 783: -Error: Invalid date/time: line std::istream& -While parsing file "$sourcepath/test/garbage-input.dat", line 789: -Error: Unexpected whitespace at beginning of line -end test diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b440d2ed..de7fdd26 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -12,7 +12,7 @@ if (BUILD_LIBRARY) endif() add_ledger_test(UtilTests) - add_executable(MathTests t_amount.cc t_commodity.cc t_balance.cc t_expr.cc) + add_executable(MathTests t_amount.cc t_commodity.cc t_balance.cc t_expr.cc t_value.cc) set_source_files_properties(t_amount.cc PROPERTIES COMPILE_FLAGS "-Wno-unused-comparison") if (CMAKE_SYSTEM_NAME STREQUAL Darwin AND HAVE_BOOST_PYTHON) target_link_libraries(MathTests ${PYTHON_LIBRARIES}) diff --git a/test/unit/t_value.cc b/test/unit/t_value.cc new file mode 100644 index 00000000..e8367bbe --- /dev/null +++ b/test/unit/t_value.cc @@ -0,0 +1,714 @@ +#define BOOST_TEST_DYN_LINK + +#include <boost/test/unit_test.hpp> + +#include <system.hh> + +#include "value.h" + +using namespace ledger; + +struct value_fixture { + value_fixture() { + times_initialize(); + amount_t::initialize(); + value_t::initialize(); + + + // Cause the display precision for dollars to be initialized to 2. + amount_t x1("$1.00"); + BOOST_CHECK(x1); + + amount_t::stream_fullstrings = true; // make reports from UnitTests accurate + } + + ~value_fixture() + { + amount_t::stream_fullstrings = false; + amount_t::shutdown(); + times_shutdown(); + value_t::shutdown(); + } +}; + +BOOST_FIXTURE_TEST_SUITE(value, value_fixture) + +BOOST_AUTO_TEST_CASE(testConstructors) +{ + value_t::sequence_t s1; + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_t(NULL))); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(2L); + value_t v6(4UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("3 EUR")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("tag"), true); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); +} + +BOOST_AUTO_TEST_CASE(testAssignment) +{ + value_t::sequence_t s1; + value_t v1; + value_t v2 = true; + value_t v3 = boost::posix_time::from_time_t(time_t(NULL)); + value_t v4 = date_t(parse_date("2014/08/14")); + value_t v5 = -2L; + value_t v6 = 4UL; + value_t v7 = 1.00; + value_t v8 = amount_t("4 GBP"); + value_t v9 = balance_t("3 EUR"); + value_t v10 = mask_t("regex"); + value_t v11 = s1; + value_t v12 = value_t(string("$1")); + value_t v13 = value_t("2 CAD"); + value_t v14 = value_t("comment", true); + value_t v15 = value_t(string("tag"), true); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); +} + +BOOST_AUTO_TEST_CASE(testEquality) +{ + struct tm localtime; + strptime("10 February 2010", "%d %b %Y", &localtime); + time_t time_var = mktime(&localtime); + value_t::sequence_t s1; + + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_var)); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(2L); + value_t v6(2UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + value_t v16; + + BOOST_CHECK_EQUAL(v1, value_t()); + BOOST_CHECK_EQUAL(v2, value_t(true)); + BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(time_var))); + BOOST_CHECK(!(v4 == value_t(date_t(parse_date("2014/08/15"))))); + + value_t v19(amount_t("2")); + value_t v20(balance_t("2")); + BOOST_CHECK_EQUAL(v5, v6); + BOOST_CHECK_EQUAL(v5, v19); + BOOST_CHECK_EQUAL(v5, v20); + BOOST_CHECK(v19 == v5); + BOOST_CHECK(v19 == v20); + BOOST_CHECK(v19 == value_t(amount_t("2"))); + BOOST_CHECK(v20 == v5); + BOOST_CHECK(v20 == v19); + BOOST_CHECK(v20 == value_t(balance_t(2L))); + BOOST_CHECK(v14 == v15); + BOOST_CHECK(v10 == value_t(mask_t("regex"))); + BOOST_CHECK(v11 == value_t(s1)); + + BOOST_CHECK_THROW(v8 == v10, value_error); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); + BOOST_CHECK(v19.valid()); + BOOST_CHECK(v20.valid()); +} + +BOOST_AUTO_TEST_CASE(testSequence) +{ + value_t::sequence_t s1; + value_t v1(s1); + BOOST_CHECK(v1.is_sequence()); + v1.push_back(value_t(2L)); + v1.push_back(value_t("3 GBP")); + + value_t v2("3 GBP"); + value_t seq(v1); + const value_t v3(seq); + + value_t::sequence_t::iterator i = std::find(seq.begin(), seq.end(), v2); + if (i != seq.end()) + BOOST_CHECK(v2 == *i); + + value_t::sequence_t::const_iterator j = std::find(v3.begin(), v3.end(), v2); + if (j != v3.end()) + BOOST_CHECK(v2 == *j); + + BOOST_CHECK(v2 == seq[1]); + BOOST_CHECK(v2 == v3[1]); + v1.pop_back(); + v1.pop_back(); + v1.push_front(v2); + v1.push_front(value_t(2L)); + BOOST_CHECK(v2 == v1[1]); + BOOST_CHECK(seq == v1); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(seq.valid()); +} + +BOOST_AUTO_TEST_CASE(testAddition) +{ + struct tm localtime; + strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime); + time_t time_var = mktime(&localtime); + value_t::sequence_t s1; + + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_var)); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(2L); + value_t v6(2UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + value_t v16(amount_t("2")); + + v14 += v15; + BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment"), true)); + v14 += v12; + BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment$1.00"), true)); + + v3 += value_t(2L); + strptime("10 February 2010 00:00:02", "%d %b %Y %H:%M:%S", &localtime); + BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime)))); + v3 += value_t(amount_t("2")); + strptime("10 February 2010 00:00:04", "%d %b %Y %H:%M:%S", &localtime); + BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime)))); + + v4 += value_t(2L); + BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/16")))); + v4 += value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/18")))); + + v5 += value_t(2L); + BOOST_CHECK_EQUAL(v5, value_t(4L)); + v5 += value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v5, value_t(amount_t("6"))); + v5 += v8; + + v16 += value_t(2L); + v16 += value_t(amount_t("2")); + v16 += v8; + BOOST_CHECK_EQUAL(v5, v16); + + v8 += value_t("6"); + BOOST_CHECK_EQUAL(v8, v16); + + value_t v17(6L); + v17 += value_t(amount_t("4 GBP")); + BOOST_CHECK_EQUAL(v8, v17); + + value_t v18(6L); + v18 += v9; + value_t v19(amount_t("6")); + v19 += v9; + BOOST_CHECK_EQUAL(v18, v19); + + v9 += value_t(2L); + v9 += value_t(amount_t("4")); + v9 += v19; + v18 += v19; + BOOST_CHECK_EQUAL(v9, v18); + + value_t v20(s1); + v11 += value_t(2L); + v11 += value_t("4 GBP"); + BOOST_CHECK_THROW(v11 += v20,value_error); + BOOST_CHECK_THROW(v10 += v8, value_error); + + v20 += value_t(2L); + v20 += value_t("4 GBP"); + BOOST_CHECK_EQUAL(v11, v20); + v11 += v20; + v20 += v20; + BOOST_CHECK_EQUAL(v11, v20); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); + BOOST_CHECK(v16.valid()); + BOOST_CHECK(v17.valid()); + BOOST_CHECK(v18.valid()); + BOOST_CHECK(v19.valid()); + BOOST_CHECK(v20.valid()); +} + +BOOST_AUTO_TEST_CASE(testSubtraction) +{ + struct tm localtime; + strptime("10 February 2010 00:00:04", "%d %b %Y %H:%M:%S", &localtime); + time_t time_var = mktime(&localtime); + value_t::sequence_t s1; + + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_var)); + value_t v4(date_t(parse_date("2014/08/18"))); + value_t v5(6L); + value_t v6(6UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + value_t v16(amount_t("6")); + + v3 -= value_t(2L); + strptime("10 February 2010 00:00:02", "%d %b %Y %H:%M:%S", &localtime); + BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime)))); + v3 -= value_t(amount_t("2")); + strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime); + BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime)))); + + v4 -= value_t(2L); + BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/16")))); + v4 -= value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/14")))); + + v5 -= value_t(2L); + BOOST_CHECK_EQUAL(v5, value_t(4L)); + v5 -= value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v5, value_t(amount_t("2"))); + v5 -= v8; + + v16 -= value_t(2L); + v16 -= value_t(amount_t("2")); + v16 -= v8; + BOOST_CHECK_EQUAL(v5, v16); + + v8 -= value_t("2"); + BOOST_CHECK_EQUAL(-v8, v16); + + value_t v18(6L); + v18 -= v9; + value_t v19(amount_t("6")); + v19 -= v9; + BOOST_CHECK_EQUAL(v18, v19); + + v9 -= value_t(-2L); + v9 -= value_t(amount_t("-10")); + v9 -= value_t(amount_t("12 GBP")); + v9 -= v19; + BOOST_CHECK_EQUAL(v9, v18); + v18 -=v19; + BOOST_CHECK_EQUAL(v18, value_t("0")); + + value_t v20(s1); + value_t v21(2L); + value_t v22("4 GBP"); + v11.push_back(v21); + v11.push_back(v22); + BOOST_CHECK_THROW(v11 -= v20,value_error); + BOOST_CHECK_THROW(v10 -= v8, value_error); + + v20.push_back(v21); + v20.push_back(v22); + v11 -= v20; + value_t v23(s1); + v23.push_back(value_t(0L)); + v23.push_back(value_t("0")); + BOOST_CHECK_EQUAL(v11, v23); + v20 -= v21; + v20 -= v22; + BOOST_CHECK_EQUAL(v20, value_t(s1)); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); + BOOST_CHECK(v16.valid()); + BOOST_CHECK(v18.valid()); + BOOST_CHECK(v19.valid()); + BOOST_CHECK(v20.valid()); +} + +BOOST_AUTO_TEST_CASE(testMultiplication) +{ + struct tm localtime; + strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime); + time_t time_var = mktime(&localtime); + value_t::sequence_t s1; + + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_var)); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(2L); + value_t v6(2UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + value_t v16(amount_t("2")); + + v14 *= value_t(2L); + BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment"), true)); + + v5 *= value_t(2L); + BOOST_CHECK_EQUAL(v5, value_t(4L)); + v5 *= value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v5, value_t(amount_t("8"))); + + v16 *= value_t(2L); + v16 *= value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v5, v16); + + v8 *= v9; + BOOST_CHECK_EQUAL(v8, value_t("16 GBP")); + + value_t v17(v9); + v9 *= value_t(2L); + BOOST_CHECK_EQUAL(v9, value_t("8 GBP")); + v17 += value_t(2L); + v17 *= value_t(2L); + value_t v18("8 GBP"); + v18 += value_t(4L); + BOOST_CHECK_EQUAL(v17, v18); + + value_t v20(s1); + v11.push_back(value_t(2L)); + v11.push_back(value_t("2 GBP")); + v20.push_back(value_t(4L)); + v20.push_back(value_t("4 GBP")); + v11 *= value_t(2L); + BOOST_CHECK_EQUAL(v11 ,v20); + + BOOST_CHECK_THROW(v10 *= v8, value_error); + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); + BOOST_CHECK(v16.valid()); + BOOST_CHECK(v17.valid()); + BOOST_CHECK(v18.valid()); +} + +BOOST_AUTO_TEST_CASE(testDivision) +{ + struct tm localtime; + strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime); + time_t time_var = mktime(&localtime); + value_t::sequence_t s1; + + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_var)); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(8L); + value_t v6(2UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + value_t v16(amount_t("8")); + + v5 /= value_t(2L); + BOOST_CHECK_EQUAL(v5, value_t(4L)); + v5 /= value_t(amount_t("8")); + BOOST_CHECK_EQUAL(v5, value_t(amount_t("2"))); + + v16 /= value_t(2L); + v16 /= value_t(amount_t("2")); + BOOST_CHECK_EQUAL(v5, v16); + + v8 /= v9; + v8 /= value_t(balance_t(2L)); + BOOST_CHECK_EQUAL(v8, value_t("0.5 GBP")); + + value_t v17(v9); + v9 /= value_t(2L); + BOOST_CHECK_EQUAL(v9, value_t("2 GBP")); + v17 /= value_t("2 GBP"); + v17 /= value_t("2"); + BOOST_CHECK_EQUAL(v17, value_t(balance_t("1 GBP"))); + + BOOST_CHECK_THROW(v10 /= v8, value_error); + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); + BOOST_CHECK(v16.valid()); + BOOST_CHECK(v17.valid()); +} + +BOOST_AUTO_TEST_CASE(testType) +{ + value_t::sequence_t s1; + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_t(NULL))); + value_t v4(date_t(parse_date("2014/08/14"))); + value_t v5(2L); + value_t v6(4UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("3 EUR")); + value_t v10(mask_t("regex")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string("tag"), true); + + BOOST_CHECK(v1.is_null()); + BOOST_CHECK(v2.is_boolean()); + BOOST_CHECK(v3.is_datetime()); + BOOST_CHECK(v4.is_date()); + BOOST_CHECK(v5.is_long()); + BOOST_CHECK(v6.is_amount()); + BOOST_CHECK(v7.is_amount()); + BOOST_CHECK(v8.is_amount()); + BOOST_CHECK(v9.is_balance()); + BOOST_CHECK(v10.is_mask()); + BOOST_CHECK(v11.is_sequence()); + BOOST_CHECK(v12.is_amount()); + BOOST_CHECK(v13.is_amount()); + BOOST_CHECK(v14.is_string()); + BOOST_CHECK(v15.is_string()); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); +} + +BOOST_AUTO_TEST_CASE(testForZero) +{ + value_t::sequence_t s1; + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_t(NULL))); + value_t v4(date_t(0)); + value_t v5(2L); + value_t v6(0UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("0")); + value_t v10(mask_t("")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("2 CAD"); + value_t v14("comment", true); + value_t v15(string(""), true); + + BOOST_CHECK(v1.is_null()); + BOOST_CHECK(v2.is_nonzero()); + BOOST_CHECK(!v3.is_zero()); + BOOST_CHECK(v4.is_nonzero()); + BOOST_CHECK(v5.is_nonzero()); + BOOST_CHECK(v6.is_realzero()); + BOOST_CHECK(v7.is_nonzero()); + BOOST_CHECK(v8.is_nonzero()); + BOOST_CHECK(v9.is_zero()); + BOOST_CHECK_THROW(v10.is_zero(), value_error); + BOOST_CHECK(v11.is_zero()); + BOOST_CHECK(v12.is_nonzero()); + BOOST_CHECK(v13.is_nonzero()); + BOOST_CHECK(v14.is_nonzero()); + BOOST_CHECK(v15.is_zero()); + + v11.push_back(v6); + BOOST_CHECK(v11.is_nonzero()); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); +} + +BOOST_AUTO_TEST_CASE(testNegation) +{ + value_t::sequence_t s1; + value_t v1; + value_t v2(true); + value_t v3(boost::posix_time::from_time_t(time_t(NULL))); + value_t v4(date_t(parse_date("2014/08/09"))); + value_t v5(2L); + value_t v6(0UL); + value_t v7(1.00); + value_t v8(amount_t("4 GBP")); + value_t v9(balance_t("4 GBP")); + value_t v10(mask_t("")); + value_t v11(s1); + value_t v12(string("$1")); + value_t v13("$-1"); + value_t v14("comment", true); + value_t v15(string("comment"), true); + + BOOST_CHECK_THROW(v1.negated(), value_error); + BOOST_CHECK_EQUAL(v2.negated(), value_t(false)); + v5.in_place_negate(); + BOOST_CHECK_EQUAL(v5, value_t(-2L)); + v8.in_place_negate(); + v9.in_place_negate(); + BOOST_CHECK_EQUAL(v8, v9); + BOOST_CHECK_THROW(v10.negated(), value_error); + BOOST_CHECK_EQUAL(-v12, v13); + BOOST_CHECK_THROW(-v14, value_error); + + BOOST_CHECK(v1.valid()); + BOOST_CHECK(v2.valid()); + BOOST_CHECK(v3.valid()); + BOOST_CHECK(v4.valid()); + BOOST_CHECK(v5.valid()); + BOOST_CHECK(v6.valid()); + BOOST_CHECK(v7.valid()); + BOOST_CHECK(v8.valid()); + BOOST_CHECK(v9.valid()); + BOOST_CHECK(v10.valid()); + BOOST_CHECK(v11.valid()); + BOOST_CHECK(v12.valid()); + BOOST_CHECK(v13.valid()); + BOOST_CHECK(v14.valid()); + BOOST_CHECK(v15.valid()); +} + +BOOST_AUTO_TEST_SUITE_END() + |