1*b0d29bc4SBrooks Davis // Copyright 2011 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "engine/filters.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis #include <algorithm>
32*b0d29bc4SBrooks Davis #include <stdexcept>
33*b0d29bc4SBrooks Davis
34*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
35*b0d29bc4SBrooks Davis #include "utils/fs/exceptions.hpp"
36*b0d29bc4SBrooks Davis #include "utils/logging/macros.hpp"
37*b0d29bc4SBrooks Davis #include "utils/optional.ipp"
38*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
39*b0d29bc4SBrooks Davis
40*b0d29bc4SBrooks Davis namespace fs = utils::fs;
41*b0d29bc4SBrooks Davis
42*b0d29bc4SBrooks Davis using utils::none;
43*b0d29bc4SBrooks Davis using utils::optional;
44*b0d29bc4SBrooks Davis
45*b0d29bc4SBrooks Davis
46*b0d29bc4SBrooks Davis /// Constructs a filter.
47*b0d29bc4SBrooks Davis ///
48*b0d29bc4SBrooks Davis /// \param test_program_ The name of the test program or of the subdirectory to
49*b0d29bc4SBrooks Davis /// match.
50*b0d29bc4SBrooks Davis /// \param test_case_ The name of the test case to match.
test_filter(const fs::path & test_program_,const std::string & test_case_)51*b0d29bc4SBrooks Davis engine::test_filter::test_filter(const fs::path& test_program_,
52*b0d29bc4SBrooks Davis const std::string& test_case_) :
53*b0d29bc4SBrooks Davis test_program(test_program_),
54*b0d29bc4SBrooks Davis test_case(test_case_)
55*b0d29bc4SBrooks Davis {
56*b0d29bc4SBrooks Davis }
57*b0d29bc4SBrooks Davis
58*b0d29bc4SBrooks Davis
59*b0d29bc4SBrooks Davis /// Parses a user-provided test filter.
60*b0d29bc4SBrooks Davis ///
61*b0d29bc4SBrooks Davis /// \param str The user-provided string representing a filter for tests. Must
62*b0d29bc4SBrooks Davis /// be of the form <test_program%gt;[:<test_case%gt;].
63*b0d29bc4SBrooks Davis ///
64*b0d29bc4SBrooks Davis /// \return The parsed filter.
65*b0d29bc4SBrooks Davis ///
66*b0d29bc4SBrooks Davis /// \throw std::runtime_error If the provided filter is invalid.
67*b0d29bc4SBrooks Davis engine::test_filter
parse(const std::string & str)68*b0d29bc4SBrooks Davis engine::test_filter::parse(const std::string& str)
69*b0d29bc4SBrooks Davis {
70*b0d29bc4SBrooks Davis if (str.empty())
71*b0d29bc4SBrooks Davis throw std::runtime_error("Test filter cannot be empty");
72*b0d29bc4SBrooks Davis
73*b0d29bc4SBrooks Davis const std::string::size_type pos = str.find(':');
74*b0d29bc4SBrooks Davis if (pos == 0)
75*b0d29bc4SBrooks Davis throw std::runtime_error(F("Program name component in '%s' is empty")
76*b0d29bc4SBrooks Davis % str);
77*b0d29bc4SBrooks Davis if (pos == str.length() - 1)
78*b0d29bc4SBrooks Davis throw std::runtime_error(F("Test case component in '%s' is empty")
79*b0d29bc4SBrooks Davis % str);
80*b0d29bc4SBrooks Davis
81*b0d29bc4SBrooks Davis try {
82*b0d29bc4SBrooks Davis const fs::path test_program_(str.substr(0, pos));
83*b0d29bc4SBrooks Davis if (test_program_.is_absolute())
84*b0d29bc4SBrooks Davis throw std::runtime_error(F("Program name '%s' must be relative "
85*b0d29bc4SBrooks Davis "to the test suite, not absolute") %
86*b0d29bc4SBrooks Davis test_program_.str());
87*b0d29bc4SBrooks Davis if (pos == std::string::npos) {
88*b0d29bc4SBrooks Davis LD(F("Parsed user filter '%s': test program '%s', no test case") %
89*b0d29bc4SBrooks Davis str % test_program_.str());
90*b0d29bc4SBrooks Davis return test_filter(test_program_, "");
91*b0d29bc4SBrooks Davis } else {
92*b0d29bc4SBrooks Davis const std::string test_case_(str.substr(pos + 1));
93*b0d29bc4SBrooks Davis LD(F("Parsed user filter '%s': test program '%s', test case '%s'") %
94*b0d29bc4SBrooks Davis str % test_program_.str() % test_case_);
95*b0d29bc4SBrooks Davis return test_filter(test_program_, test_case_);
96*b0d29bc4SBrooks Davis }
97*b0d29bc4SBrooks Davis } catch (const fs::error& e) {
98*b0d29bc4SBrooks Davis throw std::runtime_error(F("Invalid path in filter '%s': %s") % str %
99*b0d29bc4SBrooks Davis e.what());
100*b0d29bc4SBrooks Davis }
101*b0d29bc4SBrooks Davis }
102*b0d29bc4SBrooks Davis
103*b0d29bc4SBrooks Davis
104*b0d29bc4SBrooks Davis /// Formats a filter for user presentation.
105*b0d29bc4SBrooks Davis ///
106*b0d29bc4SBrooks Davis /// \return A user-friendly string representing the filter. Note that this does
107*b0d29bc4SBrooks Davis /// not necessarily match the string the user provided: in particular, the path
108*b0d29bc4SBrooks Davis /// may have been internally normalized.
109*b0d29bc4SBrooks Davis std::string
str(void) const110*b0d29bc4SBrooks Davis engine::test_filter::str(void) const
111*b0d29bc4SBrooks Davis {
112*b0d29bc4SBrooks Davis if (!test_case.empty())
113*b0d29bc4SBrooks Davis return F("%s:%s") % test_program % test_case;
114*b0d29bc4SBrooks Davis else
115*b0d29bc4SBrooks Davis return test_program.str();
116*b0d29bc4SBrooks Davis }
117*b0d29bc4SBrooks Davis
118*b0d29bc4SBrooks Davis
119*b0d29bc4SBrooks Davis /// Checks if this filter contains another.
120*b0d29bc4SBrooks Davis ///
121*b0d29bc4SBrooks Davis /// \param other The filter to compare to.
122*b0d29bc4SBrooks Davis ///
123*b0d29bc4SBrooks Davis /// \return True if this filter contains the other filter or if they are equal.
124*b0d29bc4SBrooks Davis bool
contains(const test_filter & other) const125*b0d29bc4SBrooks Davis engine::test_filter::contains(const test_filter& other) const
126*b0d29bc4SBrooks Davis {
127*b0d29bc4SBrooks Davis if (*this == other)
128*b0d29bc4SBrooks Davis return true;
129*b0d29bc4SBrooks Davis else
130*b0d29bc4SBrooks Davis return test_case.empty() && test_program.is_parent_of(
131*b0d29bc4SBrooks Davis other.test_program);
132*b0d29bc4SBrooks Davis }
133*b0d29bc4SBrooks Davis
134*b0d29bc4SBrooks Davis
135*b0d29bc4SBrooks Davis /// Checks if this filter matches a given test program name or subdirectory.
136*b0d29bc4SBrooks Davis ///
137*b0d29bc4SBrooks Davis /// \param test_program_ The test program to compare to.
138*b0d29bc4SBrooks Davis ///
139*b0d29bc4SBrooks Davis /// \return Whether the filter matches the test program. This is a superset of
140*b0d29bc4SBrooks Davis /// matches_test_case.
141*b0d29bc4SBrooks Davis bool
matches_test_program(const fs::path & test_program_) const142*b0d29bc4SBrooks Davis engine::test_filter::matches_test_program(const fs::path& test_program_) const
143*b0d29bc4SBrooks Davis {
144*b0d29bc4SBrooks Davis if (test_program == test_program_)
145*b0d29bc4SBrooks Davis return true;
146*b0d29bc4SBrooks Davis else {
147*b0d29bc4SBrooks Davis // Check if the filter matches a subdirectory of the test program.
148*b0d29bc4SBrooks Davis // The test case must be empty because we don't want foo:bar to match
149*b0d29bc4SBrooks Davis // foo/baz.
150*b0d29bc4SBrooks Davis return (test_case.empty() && test_program.is_parent_of(test_program_));
151*b0d29bc4SBrooks Davis }
152*b0d29bc4SBrooks Davis }
153*b0d29bc4SBrooks Davis
154*b0d29bc4SBrooks Davis
155*b0d29bc4SBrooks Davis /// Checks if this filter matches a given test case identifier.
156*b0d29bc4SBrooks Davis ///
157*b0d29bc4SBrooks Davis /// \param test_program_ The test program to compare to.
158*b0d29bc4SBrooks Davis /// \param test_case_ The test case to compare to.
159*b0d29bc4SBrooks Davis ///
160*b0d29bc4SBrooks Davis /// \return Whether the filter matches the test case.
161*b0d29bc4SBrooks Davis bool
matches_test_case(const fs::path & test_program_,const std::string & test_case_) const162*b0d29bc4SBrooks Davis engine::test_filter::matches_test_case(const fs::path& test_program_,
163*b0d29bc4SBrooks Davis const std::string& test_case_) const
164*b0d29bc4SBrooks Davis {
165*b0d29bc4SBrooks Davis if (matches_test_program(test_program_)) {
166*b0d29bc4SBrooks Davis return test_case.empty() || test_case == test_case_;
167*b0d29bc4SBrooks Davis } else
168*b0d29bc4SBrooks Davis return false;
169*b0d29bc4SBrooks Davis }
170*b0d29bc4SBrooks Davis
171*b0d29bc4SBrooks Davis
172*b0d29bc4SBrooks Davis /// Less-than comparison for sorting purposes.
173*b0d29bc4SBrooks Davis ///
174*b0d29bc4SBrooks Davis /// \param other The filter to compare to.
175*b0d29bc4SBrooks Davis ///
176*b0d29bc4SBrooks Davis /// \return True if this filter sorts before the other filter.
177*b0d29bc4SBrooks Davis bool
operator <(const test_filter & other) const178*b0d29bc4SBrooks Davis engine::test_filter::operator<(const test_filter& other) const
179*b0d29bc4SBrooks Davis {
180*b0d29bc4SBrooks Davis return (
181*b0d29bc4SBrooks Davis test_program < other.test_program ||
182*b0d29bc4SBrooks Davis (test_program == other.test_program && test_case < other.test_case));
183*b0d29bc4SBrooks Davis }
184*b0d29bc4SBrooks Davis
185*b0d29bc4SBrooks Davis
186*b0d29bc4SBrooks Davis /// Equality comparison.
187*b0d29bc4SBrooks Davis ///
188*b0d29bc4SBrooks Davis /// \param other The filter to compare to.
189*b0d29bc4SBrooks Davis ///
190*b0d29bc4SBrooks Davis /// \return True if this filter is equal to the other filter.
191*b0d29bc4SBrooks Davis bool
operator ==(const test_filter & other) const192*b0d29bc4SBrooks Davis engine::test_filter::operator==(const test_filter& other) const
193*b0d29bc4SBrooks Davis {
194*b0d29bc4SBrooks Davis return test_program == other.test_program && test_case == other.test_case;
195*b0d29bc4SBrooks Davis }
196*b0d29bc4SBrooks Davis
197*b0d29bc4SBrooks Davis
198*b0d29bc4SBrooks Davis /// Non-equality comparison.
199*b0d29bc4SBrooks Davis ///
200*b0d29bc4SBrooks Davis /// \param other The filter to compare to.
201*b0d29bc4SBrooks Davis ///
202*b0d29bc4SBrooks Davis /// \return True if this filter is different than the other filter.
203*b0d29bc4SBrooks Davis bool
operator !=(const test_filter & other) const204*b0d29bc4SBrooks Davis engine::test_filter::operator!=(const test_filter& other) const
205*b0d29bc4SBrooks Davis {
206*b0d29bc4SBrooks Davis return !(*this == other);
207*b0d29bc4SBrooks Davis }
208*b0d29bc4SBrooks Davis
209*b0d29bc4SBrooks Davis
210*b0d29bc4SBrooks Davis /// Injects the object into a stream.
211*b0d29bc4SBrooks Davis ///
212*b0d29bc4SBrooks Davis /// \param output The stream into which to inject the object.
213*b0d29bc4SBrooks Davis /// \param object The object to format.
214*b0d29bc4SBrooks Davis ///
215*b0d29bc4SBrooks Davis /// \return The output stream.
216*b0d29bc4SBrooks Davis std::ostream&
operator <<(std::ostream & output,const test_filter & object)217*b0d29bc4SBrooks Davis engine::operator<<(std::ostream& output, const test_filter& object)
218*b0d29bc4SBrooks Davis {
219*b0d29bc4SBrooks Davis if (object.test_case.empty()) {
220*b0d29bc4SBrooks Davis output << F("test_filter{test_program=%s}") % object.test_program;
221*b0d29bc4SBrooks Davis } else {
222*b0d29bc4SBrooks Davis output << F("test_filter{test_program=%s, test_case=%s}")
223*b0d29bc4SBrooks Davis % object.test_program % object.test_case;
224*b0d29bc4SBrooks Davis }
225*b0d29bc4SBrooks Davis return output;
226*b0d29bc4SBrooks Davis }
227*b0d29bc4SBrooks Davis
228*b0d29bc4SBrooks Davis
229*b0d29bc4SBrooks Davis /// Constructs a new set of filters.
230*b0d29bc4SBrooks Davis ///
231*b0d29bc4SBrooks Davis /// \param filters_ The filters themselves; if empty, no filters are applied.
test_filters(const std::set<test_filter> & filters_)232*b0d29bc4SBrooks Davis engine::test_filters::test_filters(const std::set< test_filter >& filters_) :
233*b0d29bc4SBrooks Davis _filters(filters_)
234*b0d29bc4SBrooks Davis {
235*b0d29bc4SBrooks Davis }
236*b0d29bc4SBrooks Davis
237*b0d29bc4SBrooks Davis
238*b0d29bc4SBrooks Davis /// Checks if a given test program matches the set of filters.
239*b0d29bc4SBrooks Davis ///
240*b0d29bc4SBrooks Davis /// This is provided as an optimization only, and the results of this function
241*b0d29bc4SBrooks Davis /// are less specific than those of match_test_case. Checking for the matching
242*b0d29bc4SBrooks Davis /// of a test program should be done before loading the list of test cases from
243*b0d29bc4SBrooks Davis /// a program, so as to avoid the delay in executing the test program, but
244*b0d29bc4SBrooks Davis /// match_test_case must still be called afterwards.
245*b0d29bc4SBrooks Davis ///
246*b0d29bc4SBrooks Davis /// \param name The test program to check against the filters.
247*b0d29bc4SBrooks Davis ///
248*b0d29bc4SBrooks Davis /// \return True if the provided identifier matches any filter.
249*b0d29bc4SBrooks Davis bool
match_test_program(const fs::path & name) const250*b0d29bc4SBrooks Davis engine::test_filters::match_test_program(const fs::path& name) const
251*b0d29bc4SBrooks Davis {
252*b0d29bc4SBrooks Davis if (_filters.empty())
253*b0d29bc4SBrooks Davis return true;
254*b0d29bc4SBrooks Davis
255*b0d29bc4SBrooks Davis bool matches = false;
256*b0d29bc4SBrooks Davis for (std::set< test_filter >::const_iterator iter = _filters.begin();
257*b0d29bc4SBrooks Davis !matches && iter != _filters.end(); iter++) {
258*b0d29bc4SBrooks Davis matches = (*iter).matches_test_program(name);
259*b0d29bc4SBrooks Davis }
260*b0d29bc4SBrooks Davis return matches;
261*b0d29bc4SBrooks Davis }
262*b0d29bc4SBrooks Davis
263*b0d29bc4SBrooks Davis
264*b0d29bc4SBrooks Davis /// Checks if a given test case identifier matches the set of filters.
265*b0d29bc4SBrooks Davis ///
266*b0d29bc4SBrooks Davis /// \param test_program The test program to check against the filters.
267*b0d29bc4SBrooks Davis /// \param test_case The test case to check against the filters.
268*b0d29bc4SBrooks Davis ///
269*b0d29bc4SBrooks Davis /// \return A boolean indicating if the test case is matched by any filter and,
270*b0d29bc4SBrooks Davis /// if true, a string containing the filter name. The string is empty when
271*b0d29bc4SBrooks Davis /// there are no filters defined.
272*b0d29bc4SBrooks Davis engine::test_filters::match
match_test_case(const fs::path & test_program,const std::string & test_case) const273*b0d29bc4SBrooks Davis engine::test_filters::match_test_case(const fs::path& test_program,
274*b0d29bc4SBrooks Davis const std::string& test_case) const
275*b0d29bc4SBrooks Davis {
276*b0d29bc4SBrooks Davis if (_filters.empty()) {
277*b0d29bc4SBrooks Davis INV(match_test_program(test_program));
278*b0d29bc4SBrooks Davis return match(true, none);
279*b0d29bc4SBrooks Davis }
280*b0d29bc4SBrooks Davis
281*b0d29bc4SBrooks Davis optional< test_filter > found = none;
282*b0d29bc4SBrooks Davis for (std::set< test_filter >::const_iterator iter = _filters.begin();
283*b0d29bc4SBrooks Davis !found && iter != _filters.end(); iter++) {
284*b0d29bc4SBrooks Davis if ((*iter).matches_test_case(test_program, test_case))
285*b0d29bc4SBrooks Davis found = *iter;
286*b0d29bc4SBrooks Davis }
287*b0d29bc4SBrooks Davis INV(!found || match_test_program(test_program));
288*b0d29bc4SBrooks Davis return match(static_cast< bool >(found), found);
289*b0d29bc4SBrooks Davis }
290*b0d29bc4SBrooks Davis
291*b0d29bc4SBrooks Davis
292*b0d29bc4SBrooks Davis /// Calculates the filters that have not matched any tests.
293*b0d29bc4SBrooks Davis ///
294*b0d29bc4SBrooks Davis /// \param matched The filters that did match some tests. This must be a subset
295*b0d29bc4SBrooks Davis /// of the filters held by this object.
296*b0d29bc4SBrooks Davis ///
297*b0d29bc4SBrooks Davis /// \return The set of filters that have not been used.
298*b0d29bc4SBrooks Davis std::set< engine::test_filter >
difference(const std::set<test_filter> & matched) const299*b0d29bc4SBrooks Davis engine::test_filters::difference(const std::set< test_filter >& matched) const
300*b0d29bc4SBrooks Davis {
301*b0d29bc4SBrooks Davis PRE(std::includes(_filters.begin(), _filters.end(),
302*b0d29bc4SBrooks Davis matched.begin(), matched.end()));
303*b0d29bc4SBrooks Davis
304*b0d29bc4SBrooks Davis std::set< test_filter > filters;
305*b0d29bc4SBrooks Davis std::set_difference(_filters.begin(), _filters.end(),
306*b0d29bc4SBrooks Davis matched.begin(), matched.end(),
307*b0d29bc4SBrooks Davis std::inserter(filters, filters.begin()));
308*b0d29bc4SBrooks Davis return filters;
309*b0d29bc4SBrooks Davis }
310*b0d29bc4SBrooks Davis
311*b0d29bc4SBrooks Davis
312*b0d29bc4SBrooks Davis /// Checks if a collection of filters is disjoint.
313*b0d29bc4SBrooks Davis ///
314*b0d29bc4SBrooks Davis /// \param filters The filters to check.
315*b0d29bc4SBrooks Davis ///
316*b0d29bc4SBrooks Davis /// \throw std::runtime_error If the filters are not disjoint.
317*b0d29bc4SBrooks Davis void
check_disjoint_filters(const std::set<engine::test_filter> & filters)318*b0d29bc4SBrooks Davis engine::check_disjoint_filters(const std::set< engine::test_filter >& filters)
319*b0d29bc4SBrooks Davis {
320*b0d29bc4SBrooks Davis // Yes, this is an O(n^2) algorithm. However, we can assume that the number
321*b0d29bc4SBrooks Davis // of test filters (which are provided by the user on the command line) on a
322*b0d29bc4SBrooks Davis // particular run is in the order of tens, and thus this should not cause
323*b0d29bc4SBrooks Davis // any serious performance trouble.
324*b0d29bc4SBrooks Davis for (std::set< test_filter >::const_iterator i1 = filters.begin();
325*b0d29bc4SBrooks Davis i1 != filters.end(); i1++) {
326*b0d29bc4SBrooks Davis for (std::set< test_filter >::const_iterator i2 = filters.begin();
327*b0d29bc4SBrooks Davis i2 != filters.end(); i2++) {
328*b0d29bc4SBrooks Davis const test_filter& filter1 = *i1;
329*b0d29bc4SBrooks Davis const test_filter& filter2 = *i2;
330*b0d29bc4SBrooks Davis
331*b0d29bc4SBrooks Davis if (i1 != i2 && filter1.contains(filter2)) {
332*b0d29bc4SBrooks Davis throw std::runtime_error(
333*b0d29bc4SBrooks Davis F("Filters '%s' and '%s' are not disjoint") %
334*b0d29bc4SBrooks Davis filter1.str() % filter2.str());
335*b0d29bc4SBrooks Davis }
336*b0d29bc4SBrooks Davis }
337*b0d29bc4SBrooks Davis }
338*b0d29bc4SBrooks Davis }
339*b0d29bc4SBrooks Davis
340*b0d29bc4SBrooks Davis
341*b0d29bc4SBrooks Davis /// Constructs a filters_state instance.
342*b0d29bc4SBrooks Davis ///
343*b0d29bc4SBrooks Davis /// \param filters_ The set of filters to track.
filters_state(const std::set<engine::test_filter> & filters_)344*b0d29bc4SBrooks Davis engine::filters_state::filters_state(
345*b0d29bc4SBrooks Davis const std::set< engine::test_filter >& filters_) :
346*b0d29bc4SBrooks Davis _filters(test_filters(filters_))
347*b0d29bc4SBrooks Davis {
348*b0d29bc4SBrooks Davis }
349*b0d29bc4SBrooks Davis
350*b0d29bc4SBrooks Davis
351*b0d29bc4SBrooks Davis /// Checks whether these filters match the given test program.
352*b0d29bc4SBrooks Davis ///
353*b0d29bc4SBrooks Davis /// \param test_program The test program to match against.
354*b0d29bc4SBrooks Davis ///
355*b0d29bc4SBrooks Davis /// \return True if these filters match the given test program name.
356*b0d29bc4SBrooks Davis bool
match_test_program(const fs::path & test_program) const357*b0d29bc4SBrooks Davis engine::filters_state::match_test_program(const fs::path& test_program) const
358*b0d29bc4SBrooks Davis {
359*b0d29bc4SBrooks Davis return _filters.match_test_program(test_program);
360*b0d29bc4SBrooks Davis }
361*b0d29bc4SBrooks Davis
362*b0d29bc4SBrooks Davis
363*b0d29bc4SBrooks Davis /// Checks whether these filters match the given test case.
364*b0d29bc4SBrooks Davis ///
365*b0d29bc4SBrooks Davis /// \param test_program The test program to match against.
366*b0d29bc4SBrooks Davis /// \param test_case The test case to match against.
367*b0d29bc4SBrooks Davis ///
368*b0d29bc4SBrooks Davis /// \return True if these filters match the given test case identifier.
369*b0d29bc4SBrooks Davis bool
match_test_case(const fs::path & test_program,const std::string & test_case)370*b0d29bc4SBrooks Davis engine::filters_state::match_test_case(const fs::path& test_program,
371*b0d29bc4SBrooks Davis const std::string& test_case)
372*b0d29bc4SBrooks Davis {
373*b0d29bc4SBrooks Davis engine::test_filters::match match = _filters.match_test_case(
374*b0d29bc4SBrooks Davis test_program, test_case);
375*b0d29bc4SBrooks Davis if (match.first && match.second)
376*b0d29bc4SBrooks Davis _used_filters.insert(match.second.get());
377*b0d29bc4SBrooks Davis return match.first;
378*b0d29bc4SBrooks Davis }
379*b0d29bc4SBrooks Davis
380*b0d29bc4SBrooks Davis
381*b0d29bc4SBrooks Davis /// Calculates the unused filters in this set.
382*b0d29bc4SBrooks Davis ///
383*b0d29bc4SBrooks Davis /// \return Returns the set of filters that have not matched any tests. This
384*b0d29bc4SBrooks Davis /// information is useful to report usage errors to the user.
385*b0d29bc4SBrooks Davis std::set< engine::test_filter >
unused(void) const386*b0d29bc4SBrooks Davis engine::filters_state::unused(void) const
387*b0d29bc4SBrooks Davis {
388*b0d29bc4SBrooks Davis return _filters.difference(_used_filters);
389*b0d29bc4SBrooks Davis }
390