OTest2
A C++ testing framework
scenariocase.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Ondrej Starek
3  *
4  * This file is part of OTest2
5  *
6  * OTest2 is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License,
9  * or (at your option) any later version.
10  *
11  * OTest2 is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with OTest2. If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <scenariocase.h>
20 
21 #include <assert.h>
22 #include <vector>
23 
24 #include <context.h>
25 #include <objectpath.h>
26 #include <objectrepeater.h>
27 #include <objectrepeaterfactory.h>
28 #include <parameters.h>
29 #include <reporter.h>
30 #include <runnerfilter.h>
31 #include <scenariocontainer.h>
32 #include <semanticstack.h>
33 #include <tags.h>
34 #include <tagsstack.h>
35 #include <utils.h>
36 
37 namespace OTest2 {
38 
39 
40 struct ScenarioCase::Impl {
41  std::string name;
42  std::string section_path;
43  Tags tags;
44  ObjectRepeaterFactoryPtr repeater_factory;
45 
46  /* -- registered test scenarios */
47  struct Section {
48  std::string name;
49  std::vector<Section> children;
50 
51  void filterScenario(
52  ScenarioCase::Impl* pimpl_,
53  ObjectPath& path_,
54  TagsStack& tags_,
55  ScenarioContainerPtr parent_,
56  const RunnerFilter& filter_) const;
57  };
58  std::vector<Section> sections;
59 
60  /* -- avoid copying */
61  Impl(
62  const Impl&) = delete;
63  Impl& operator = (
64  const Impl&) = delete;
65 
66  explicit Impl(
67  const std::string& name_,
68  const std::string& section_path_,
69  const Tags& tags_,
70  ObjectRepeaterFactoryPtr repeater_factory_);
71  ~Impl();
72 };
73 
74 ScenarioCase::Impl::Impl(
75  const std::string& name_,
76  const std::string& section_path_,
77  const Tags& tags_,
78  ObjectRepeaterFactoryPtr repeater_factory_) :
79  name(name_),
80  section_path(section_path_),
81  tags(tags_),
82  repeater_factory(repeater_factory_),
83  sections() {
84  assert(!name.empty() && repeater_factory != nullptr);
85 
86 }
87 
88 ScenarioCase::Impl::~Impl() {
89 
90 }
91 
92 void ScenarioCase::Impl::Section::filterScenario(
93  Impl* pimpl_,
94  ObjectPath& path_,
95  TagsStack& tags_,
96  ScenarioContainerPtr parent_,
97  const RunnerFilter& filter_) const {
98  /* -- add my name and tags into the whole path */
99  path_.pushName(name);
100  tags_.pushTags(name, pimpl_->tags);
101 
102  if(children.empty()) {
103  /* -- I am a leaf - check whether I match the filter */
104  if(!filter_.filterPath(tags_)) {
105  parent_->appendScenario(
106  std::make_shared<ScenarioCase>(
107  pimpl_->name, path_.getCurrentPath(), pimpl_->tags, pimpl_->repeater_factory));
108  }
109  }
110  else {
111  /* -- recursively iterate the children scenarios */
112  for(const auto& scenario_ : children)
113  scenario_.filterScenario(pimpl_, path_, tags_, parent_, filter_);
114  }
115 
116  /* -- pop me */
117  tags_.popTags();
118  path_.popName();
119 }
120 
122  const std::string& name_,
123  const Tags& tags_,
124  ObjectRepeaterFactoryPtr repeater_factory_) :
125  pimpl(new Impl(name_, std::string(), tags_, repeater_factory_)) {
126 
127 }
128 
130  const std::string& name_,
131  const std::string& section_path_,
132  const Tags& tags_,
133  ObjectRepeaterFactoryPtr repeater_factory_) :
134  pimpl(new Impl(name_, section_path_, tags_, repeater_factory_)) {
135 
136 }
137 
139  const std::string& name_,
140  const Tags& tags_,
141  ObjectRepeaterFactoryPtr repeater_factory_) {
142  return ScenarioCaseBuilder(name_, tags_, repeater_factory_);
143 }
144 
146  odelete(pimpl);
147 }
148 
150  TagsStack& tags_,
151  ScenarioContainerPtr parent_,
152  const RunnerFilter& filter_) const {
153  /* -- add my name nad tags into the whole path */
154  tags_.pushTags(pimpl->name, pimpl->tags);
155 
156  if(pimpl->sections.empty()) {
157  /* -- there are no scenarios -> check whether I am filtered */
158  if(!filter_.filterPath(tags_)) {
159  parent_->appendScenario(
160  std::make_shared<ScenarioCase>(
161  pimpl->name, pimpl->tags, pimpl->repeater_factory));
162  }
163  }
164  else {
165  /* -- check the scenarios */
166  ObjectPath path_;
167  for(const auto& scenario : pimpl->sections)
168  scenario.filterScenario(pimpl, path_, tags_, parent_, filter_);
169  }
170 
171  /* -- pop me */
172  tags_.popTags();
173 
174  return parent_;
175 }
176 
177 std::pair<std::string, ObjectRepeaterPtr> ScenarioCase::createRepeater(
178  const Context& context_) const {
179  return {pimpl->name, pimpl->repeater_factory->createRepeater(context_, pimpl->section_path)};
180 }
181 
183  const Context& context_) const noexcept {
184  /* -- set the section path if it's active */
185  if(!pimpl->section_path.empty())
186  context_.object_path->appendParameter("section", pimpl->section_path);
187 
188  /* -- report the object */
189  context_.reporter->enterCase(
190  context_,
191  context_.object_path->getCurrentName(),
192  context_.object_path->getCurrentParameters());
193 }
194 
196  const Context& context_) const noexcept {
197  context_.reporter->leaveCase(
198  context_,
199  context_.object_path->getCurrentName(),
200  context_.object_path->getCurrentParameters(),
201  context_.semantic_stack->top());
202 }
203 
205  assert(false);
206  return ScenarioIterPtr();
207 }
208 
209 struct ScenarioCaseBuilder::Impl {
210  ScenarioPtr scenario;
211  ScenarioCase* scenario_case;
212  std::vector<ScenarioCase::Impl::Section*> section_stack;
213 
214  /* -- avoid copying */
215  Impl(
216  const Impl&) = delete;
217  Impl& operator = (
218  const Impl&) = delete;
219 
220  explicit Impl(
221  const std::string& name_,
222  const Tags& tags_,
223  ObjectRepeaterFactoryPtr repeater_factory_);
224  ~Impl();
225 };
226 
227 ScenarioCaseBuilder::Impl::Impl(
228  const std::string& name_,
229  const Tags& tags_,
230  ObjectRepeaterFactoryPtr repeater_factory_) :
231  scenario(std::make_shared<ScenarioCase>(name_, tags_, repeater_factory_)),
232  scenario_case(static_cast<ScenarioCase*>(scenario.get())),
233  section_stack() {
234 
235 }
236 
237 ScenarioCaseBuilder::Impl::~Impl() {
238 
239 }
240 
242  const std::string& name_,
243  const Tags& tags_,
244  ObjectRepeaterFactoryPtr repeater_factory_) :
245  pimpl(new Impl(name_, tags_, repeater_factory_)) {
246 
247 }
248 
250  ScenarioCaseBuilder&& other_) :
251  pimpl(other_.pimpl) {
252  other_.pimpl = nullptr;
253 }
254 
256  odelete(pimpl);
257 }
258 
260  const std::string& name_) {
261  assert(!name_.empty());
262 
263  if(pimpl->section_stack.empty()) {
264  pimpl->scenario_case->pimpl->sections.push_back(ScenarioCase::Impl::Section{name_, {}});
265  pimpl->section_stack.push_back(&pimpl->scenario_case->pimpl->sections.back());
266  }
267  else {
268  auto top_(pimpl->section_stack.back());
269  top_->children.push_back(ScenarioCase::Impl::Section{name_, {}});
270  pimpl->section_stack.push_back(&top_->children.back());
271  }
272 
273  return *this;
274 }
275 
277  assert(!pimpl->section_stack.empty());
278  pimpl->section_stack.pop_back();
279 
280  return *this;
281 }
282 
284  return pimpl->scenario;
285 }
286 
287 } /* -- namespace OTest2 */
OTest2::ScenarioCaseBuilder::ScenarioCaseBuilder
ScenarioCaseBuilder(const ScenarioCaseBuilder &)=delete
OTest2::ScenarioCase
Scenario object of a test case.
Definition: scenariocase.h:34
OTest2::ScenarioCaseBuilder::~ScenarioCaseBuilder
~ScenarioCaseBuilder()
Dtor.
Definition: scenariocase.cpp:255
OTest2::ScenarioCaseBuilder::popSection
ScenarioCaseBuilder & popSection()
Pop section at current top.
Definition: scenariocase.cpp:276
objectrepeater.h
OTest2::ObjectPath
This is a simple object keeping path to current testing object.
Definition: objectpath.h:32
OTest2::ScenarioCase::operator=
ScenarioCase & operator=(const ScenarioCase &)=delete
OTest2::ScenarioCase::enterObject
virtual void enterObject(const Context &context_) const noexcept override
Enter the testing object.
Definition: scenariocase.cpp:182
OTest2::RunnerFilter
Generic interface of a runner filter.
Definition: runnerfilter.h:35
tags.h
OTest2::ScenarioCase::ScenarioCaseBuilder
friend class ScenarioCaseBuilder
Definition: scenariocase.h:38
tagsstack.h
OTest2::ScenarioCase::leaveObject
virtual void leaveObject(const Context &context_) const noexcept override
Report leaving of the testing object.
Definition: scenariocase.cpp:195
OTest2::ScenarioCase::getChildren
virtual ScenarioIterPtr getChildren() const override
Get iterator of children object.
Definition: scenariocase.cpp:204
reporter.h
OTest2::TagsStack::popTags
void popTags()
Pop tags at the top of the stack.
Definition: tagsstack.cpp:67
OTest2::TagsStack::pushTags
void pushTags(const std::string &name_, const Tags &tags_)
Push tags.
Definition: tagsstack.cpp:61
OTest2::ScenarioCase::filterScenario
virtual ScenarioPtr filterScenario(TagsStack &tags_, ScenarioContainerPtr parent_, const RunnerFilter &filter_) const override
Filter the scenario.
Definition: scenariocase.cpp:149
utils.h
scenariocase.h
OTest2::ScenarioCaseBuilder::operator=
ScenarioCaseBuilder & operator=(const ScenarioCaseBuilder &)=delete
objectpath.h
semanticstack.h
OTest2::ObjectRepeaterFactoryPtr
std::shared_ptr< ObjectRepeaterFactory > ObjectRepeaterFactoryPtr
Shared pointer of the object repeater factories.
Definition: objectrepeaterfactoryptr.h:27
OTest2
Definition: assertbean.h:25
OTest2::ScenarioCase::ScenarioCase
ScenarioCase(const std::string &name_, const Tags &tags_, ObjectRepeaterFactoryPtr repeater_factory_)
Ctor.
Definition: scenariocase.cpp:121
OTest2::ScenarioIterPtr
std::shared_ptr< ScenarioIter > ScenarioIterPtr
Shared pointer of the scenario iter interface.
Definition: scenarioiterptr.h:27
parameters.h
OTest2::ScenarioPtr
std::shared_ptr< Scenario > ScenarioPtr
Shared pointer of the scenario object.
Definition: scenarioptr.h:27
runnerfilter.h
OTest2::ScenarioCaseBuilder::getScenario
ScenarioPtr getScenario()
Get the build scenario.
Definition: scenariocase.cpp:283
OTest2::ScenarioCase::createRepeater
virtual std::pair< std::string, ObjectRepeaterPtr > createRepeater(const Context &context_) const override
Create repeater object for testing object represented by this scenario object.
Definition: scenariocase.cpp:177
OTest2::TagsStack
Stack of assigned tags.
Definition: tagsstack.h:36
context.h
OTest2::Tags
List of tags assigned to a testing object.
Definition: tags.h:32
OTest2::ScenarioCaseBuilder::pushSection
ScenarioCaseBuilder & pushSection(const std::string &name_)
Push a child section.
Definition: scenariocase.cpp:259
OTest2::Context
OTest2 runtime context.
Definition: context.h:38
objectrepeaterfactory.h
OTest2::ScenarioContainerPtr
std::shared_ptr< ScenarioContainer > ScenarioContainerPtr
Shared pointer to a scenario container.
Definition: scenariocontainerptr.h:27
OTest2::ScenarioCase::~ScenarioCase
virtual ~ScenarioCase()
Dtor.
Definition: scenariocase.cpp:145
OTest2::RunnerFilter::filterPath
virtual bool filterPath(const TagsStack &path_) const noexcept=0
Check whether the path should be filtered.
OTest2::ScenarioCaseBuilder
A helper class for building of a case scenario (mainly composition of test sections)
Definition: scenariocase.h:105
OTest2::ScenarioCase::createBuilder
static ScenarioCaseBuilder createBuilder(const std::string &name_, const Tags &tags_, ObjectRepeaterFactoryPtr repeater_factory_)
Create builder of the scenario case.
Definition: scenariocase.cpp:138
OTest2::odelete
void odelete(T_ *&object_)
Delete a pointer and set it invalid.
Definition: utils.h:34
scenariocontainer.h