1 /*
2  *  Created by Phil Nash on 08/02/2017.
3  *  Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
4  *
5  * Distributed under the Boost Software License, Version 1.0. (See accompanying
6  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  */
8 
9 #include "catch_matchers_string.h"
10 #include "catch_string_manip.h"
11 #include "catch_tostring.h"
12 
13 #include <regex>
14 
15 namespace Catch {
16 namespace Matchers {
17 
18     namespace StdString {
19 
CasedString(std::string const & str,CaseSensitive::Choice caseSensitivity)20         CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
21         :   m_caseSensitivity( caseSensitivity ),
22             m_str( adjustString( str ) )
23         {}
adjustString(std::string const & str) const24         std::string CasedString::adjustString( std::string const& str ) const {
25             return m_caseSensitivity == CaseSensitive::No
26                    ? toLower( str )
27                    : str;
28         }
caseSensitivitySuffix() const29         std::string CasedString::caseSensitivitySuffix() const {
30             return m_caseSensitivity == CaseSensitive::No
31                    ? " (case insensitive)"
32                    : std::string();
33         }
34 
35 
StringMatcherBase(std::string const & operation,CasedString const & comparator)36         StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
37         : m_comparator( comparator ),
38           m_operation( operation ) {
39         }
40 
describe() const41         std::string StringMatcherBase::describe() const {
42             std::string description;
43             description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
44                                         m_comparator.caseSensitivitySuffix().size());
45             description += m_operation;
46             description += ": \"";
47             description += m_comparator.m_str;
48             description += "\"";
49             description += m_comparator.caseSensitivitySuffix();
50             return description;
51         }
52 
EqualsMatcher(CasedString const & comparator)53         EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
54 
match(std::string const & source) const55         bool EqualsMatcher::match( std::string const& source ) const {
56             return m_comparator.adjustString( source ) == m_comparator.m_str;
57         }
58 
59 
ContainsMatcher(CasedString const & comparator)60         ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
61 
match(std::string const & source) const62         bool ContainsMatcher::match( std::string const& source ) const {
63             return contains( m_comparator.adjustString( source ), m_comparator.m_str );
64         }
65 
66 
StartsWithMatcher(CasedString const & comparator)67         StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
68 
match(std::string const & source) const69         bool StartsWithMatcher::match( std::string const& source ) const {
70             return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
71         }
72 
73 
EndsWithMatcher(CasedString const & comparator)74         EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
75 
match(std::string const & source) const76         bool EndsWithMatcher::match( std::string const& source ) const {
77             return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
78         }
79 
80 
81 
RegexMatcher(std::string regex,CaseSensitive::Choice caseSensitivity)82         RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}
83 
match(std::string const & matchee) const84         bool RegexMatcher::match(std::string const& matchee) const {
85             auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
86             if (m_caseSensitivity == CaseSensitive::Choice::No) {
87                 flags |= std::regex::icase;
88             }
89             auto reg = std::regex(m_regex, flags);
90             return std::regex_match(matchee, reg);
91         }
92 
describe() const93         std::string RegexMatcher::describe() const {
94             return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");
95         }
96 
97     } // namespace StdString
98 
99 
Equals(std::string const & str,CaseSensitive::Choice caseSensitivity)100     StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
101         return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
102     }
Contains(std::string const & str,CaseSensitive::Choice caseSensitivity)103     StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
104         return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
105     }
EndsWith(std::string const & str,CaseSensitive::Choice caseSensitivity)106     StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
107         return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
108     }
StartsWith(std::string const & str,CaseSensitive::Choice caseSensitivity)109     StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
110         return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
111     }
112 
Matches(std::string const & regex,CaseSensitive::Choice caseSensitivity)113     StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {
114         return StdString::RegexMatcher(regex, caseSensitivity);
115     }
116 
117 } // namespace Matchers
118 } // namespace Catch
119