summaryrefslogtreecommitdiff
path: root/vendor/bandit/bandit/run_policies/bandit_run_policy.h
blob: 6e150d8d91f4dba8f05830a82839d31275d159f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#ifndef BANDIT_BANDIT_RUN_POLICY_H
#define BANDIT_BANDIT_RUN_POLICY_H

namespace bandit { namespace detail {

  struct bandit_run_policy : public run_policy
  {
    bandit_run_policy(const char* skip_pattern, const char* only_pattern)
      : skip_pattern_(skip_pattern), only_pattern_(only_pattern)
    {}

    bool should_run(const char* it_name, const contextstack_t& contexts) const
    {
      //
      // Never run if a context has been marked as skip
      // using 'describe_skip'
      //
      if(has_context_with_hard_skip(contexts))
      {
        return false;
      }

      //
      // Always run if no patterns have been specifed
      //
      if(!has_skip_pattern() && !has_only_pattern())
      {
        return true;
      }

      if(has_only_pattern() && !has_skip_pattern())
      {
        return context_matches_only_pattern(contexts)
          || matches_only_pattern(it_name);
      }

      if(has_skip_pattern() && !has_only_pattern())
      {
        bool skip = context_matches_skip_pattern(contexts) ||
          matches_skip_pattern(it_name);
        return !skip;
      }

      //
      // If we've come this far, both 'skip' and 'only'
      // have been specified.
      //
      // If our contexts match 'only' we're still good
      // regardless of whether there's a 'skip' somewhere
      // in the context stack as well.
      if(context_matches_only_pattern(contexts))
      {
        //
        // We can still mark the current 'it' as 'skip'
        // and ignore it. We check that here.
        //
        return !matches_skip_pattern(it_name);
      }

      //
      // If we've gotten this far, the context matches 'skip'
      // We can still run this spec if it is specifically marked
      // as 'only'.
      //
      return matches_only_pattern(it_name);
    }

    private:
    bool has_context_with_hard_skip(const contextstack_t& contexts) const
    {
      contextstack_t::const_iterator it;
      for(it = contexts.begin(); it != contexts.end(); it++)
      {
        if((*it)->hard_skip())
        {
          return true;
        }
      }

      return false;
    }

    bool has_only_pattern() const
    {
      return only_pattern_.size() > 0;
    }

    bool has_skip_pattern() const
    {
      return skip_pattern_.size() > 0;
    }

    bool context_matches_only_pattern(const contextstack_t& contexts) const
    {
      contextstack_t::const_iterator it;
      for(it = contexts.begin(); it != contexts.end(); it++)
      {
        if(matches_only_pattern((*it)->name()))
        {
          return true;
        }
      }

      return false;
    }

    bool context_matches_skip_pattern(const contextstack_t& contexts) const
    {
      contextstack_t::const_iterator it;
      for(it = contexts.begin(); it != contexts.end(); it++)
      {
        if(matches_skip_pattern((*it)->name()))
        {
          return true;
        }
      }

      return false;
    }

    bool matches_only_pattern(const char* name) const
    {
      std::string n(name);
      return matches_only_pattern(n);
    }

    bool matches_only_pattern(const std::string& name) const
    {
      return matches_pattern(name, only_pattern_);
    }

    bool matches_skip_pattern(const char* name) const
    {
      std::string n(name);
      return matches_skip_pattern(n);
    }

    bool matches_skip_pattern(const std::string& name) const
    {
      return matches_pattern(name, skip_pattern_);
    }

    bool matches_pattern(const std::string& name, const std::string& pattern) const
    {
      return name.find(pattern) != std::string::npos;
    }

    private:
    std::string skip_pattern_;
    std::string only_pattern_;
  };

}}

#endif