text: /*
   *  Created by Phil Nash on 23/7/2013
   *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
   *
   *  Distributed under the Boost Software License, Version 1.0. (See accompanying
   *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
   */
  #ifndef TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
  #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
  
  #include "catch_compiler_capabilities.h"
  #include "catch_common.h"
  
  #include <string>
  #include <vector>
  #include <memory>
  
  namespace Catch {
  namespace TestCaseTracking {
  
      struct NameAndLocation {
          std::string name;
          SourceLineInfo location;
  
          NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
          friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
              return lhs.name == rhs.name
                  && lhs.location == rhs.location;
          }
      };
  
      class ITracker;
  
      using ITrackerPtr = std::shared_ptr<ITracker>;
  
      class  ITracker {
          NameAndLocation m_nameAndLocation;
  
      public:
          ITracker(NameAndLocation const& nameAndLoc) :
              m_nameAndLocation(nameAndLoc)
          {}
  
  
          // static queries
          NameAndLocation const& nameAndLocation() const {
              return m_nameAndLocation;
          }
  
          virtual ~ITracker();
  
  
          // dynamic queries
          virtual bool isComplete() const = 0; // Successfully completed or failed
          virtual bool isSuccessfullyCompleted() const = 0;
          virtual bool isOpen() const = 0; // Started but not complete
          virtual bool hasChildren() const = 0;
  
          virtual ITracker& parent() = 0;
  
          // actions
          virtual void close() = 0; // Successfully complete
          virtual void fail() = 0;
          virtual void markAsNeedingAnotherRun() = 0;
  
          virtual void addChild( ITrackerPtr const& child ) = 0;
          virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;
          virtual void openChild() = 0;
  
          // Debug/ checking
          virtual bool isSectionTracker() const = 0;
          virtual bool isGeneratorTracker() const = 0;
      };
  
      class TrackerContext {
  
          enum RunState {
              NotStarted,
              Executing,
              CompletedCycle
          };
  
          ITrackerPtr m_rootTracker;
          ITracker* m_currentTracker = nullptr;
          RunState m_runState = NotStarted;
  
      public:
  
          ITracker& startRun();
          void endRun();
  
          void startCycle();
          void completeCycle();
  
          bool completedCycle() const;
          ITracker& currentTracker();
          void setCurrentTracker( ITracker* tracker );
      };
  
      class TrackerBase : public ITracker {
      protected:
          enum CycleState {
              NotStarted,
              Executing,
              ExecutingChildren,
              NeedsAnotherRun,
              CompletedSuccessfully,
              Failed
          };
  
          using Children = std::vector<ITrackerPtr>;
          TrackerContext& m_ctx;
          ITracker* m_parent;
          Children m_children;
          CycleState m_runState = NotStarted;
  
      public:
          TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
  
          bool isComplete() const override;
          bool isSuccessfullyCompleted() const override;
          bool isOpen() const override;
          bool hasChildren() const override;
  
  
          void addChild( ITrackerPtr const& child ) override;
  
          ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;
          ITracker& parent() override;
  
          void openChild() override;
  
          bool isSectionTracker() const override;
          bool isGeneratorTracker() const override;
  
          void open();
  
          void close() override;
          void fail() override;
          void markAsNeedingAnotherRun() override;
  
      private:
          void moveToParent();
          void moveToThis();
      };
  
      class SectionTracker : public TrackerBase {
          std::vector<std::string> m_filters;
          std::string m_trimmed_name;
      public:
          SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
  
          bool isSectionTracker() const override;
  
          bool isComplete() const override;
  
          static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
  
          void tryOpen();
  
          void addInitialFilters( std::vector<std::string> const& filters );
          void addNextFilters( std::vector<std::string> const& filters );
      };
  
  } // namespace TestCaseTracking
  
  using TestCaseTracking::ITracker;
  using TestCaseTracking::TrackerContext;
  using TestCaseTracking::SectionTracker;
  
  } // namespace Catch
  
  #endif // TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
  