<commit_before>#ifndef ALEPH_TOPOLOGY_IO_GML_HH__
#define ALEPH_TOPOLOGY_IO_GML_HH__

#include <fstream>
#include <map>
#include <set>
#include <regex>
#include <stack>
#include <string>
#include <vector>

#include "utilities/String.hh"

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class GMLReader
  @brief Parses files in GML (Graph Modeling Language) format

  This is a simple reader for graphs in GML format. It suports a basic
  subset of the GML specification, viz. the specification of different
  attributes for nodes, as well as weight specifications for edges.

  Currently, the following attributes will be read:

  * \c id (for nodes)
  * \c label (for nodes)
  * \c source (for edges)
  * \c target (for edges)
  * \c weight (for edges)
*/

class GMLReader
{
public:

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  template <class SimplicialComplex> void operator()( std::ifstream& in, SimplicialComplex& K )
  {
    _nodes.clear();
    _edges.clear();

    using namespace aleph::utilities;

    using Simplex           = typename SimplicialComplex::ValueType;
    using DataType          = typename Simplex::DataType;
    using VertexType        = typename Simplex::VertexType;

    std::string line;
    std::set<std::string> levels     = { "graph", "node", "edge" };
    std::set<std::string> attributes = { "id", "label", "source", "target", "value", "weight" };

    auto isLevel = [&levels] ( const std::string& name )
    {
      return levels.find( name ) != levels.end();
    };

    auto isAttribute = [&attributes] ( const std::string& name )
    {
      return attributes.find( name ) != attributes.end();
    };

    // Specifies the current level the parser is in. May be either one
    // of the known levels above.
    std::stack<std::string> currentLevel;

    // Last level that was read by the parser. If an open bracket '[' is
    // identified, this will become the current level.
    std::string lastLevel;

    Graph graph;
    Node node;
    Edge edge;

    std::regex reAttribute = std::regex( "([[:alpha:]]+)[[:space:]]*.*" );
    std::regex reKeyValue  = std::regex( "([[:alpha:]]+)[[:space:]]+([[:alnum:]\\.]+)" );
    std::regex reLabel     = std::regex( "(label)[[:space:]]+\"([^\"]+)\"" );

    while( std::getline( in, line ) )
    {
      line = trim( line );

      // Skip comment lines. This is somewhat wasteful because I am
      // splitting the complete string even though I merely need to
      // know the first token.
      {
        auto tokens = split( line );
        if( tokens.empty() == false && ( tokens.front() == "comment" || tokens.front() == "Creator" ) )
          continue;
      }

      // Detecting a new level
      if( isLevel( line ) )
      {
        if( lastLevel.empty() )
          lastLevel = line;
        else
          throw std::runtime_error( "Encountered incorrectly-nested levels" );
      }

      // Opening a new level
      else if( line == "[" )
      {
        currentLevel.push( lastLevel );
        lastLevel = "";
      }

      // Closing a new level
      else if( line == "]" )
      {
        if( currentLevel.top() == "node" )
          _nodes.push_back( node );
        else if( currentLevel.top() == "edge" )
          _edges.push_back( edge );

        // Reset node and edge data structure to fill them again once
        // a new level is being encountered.
        node = {};
        edge = {};

        currentLevel.pop();
      }

      // Check for attributes
      else
      {
        std::smatch matches;

        auto* dict = currentLevel.top() == "node" ? &node.dict
                                                  : currentLevel.top() == "edge" ? &edge.dict
                                                                                : currentLevel.top() == "graph" ? &graph.dict
                                                                                : throw std::runtime_error( "Current level is unknown" );

        if( std::regex_match( line, matches, reAttribute ) )
        {
          auto name = matches[1];
          if( isAttribute( name ) )
          {
            // Special matching for labels
            if( name == "label" )
              std::regex_match( line, matches, reLabel );

            // Regular matching for all other attributes
            else
              std::regex_match( line, matches, reKeyValue );

            auto value = matches[2];

            if( name == "id" )
              node.id = value;
            else if( name == "source" )
              edge.source = value;
            else if( name == "target" )
              edge.target = value;

            // Just add it to the dictionary of optional values
            else
             dict->operator[]( name ) = value;
          }
          // Skip unknown attributes...
          else
          {
          }
        }
      }
    }

    // Creates nodes (vertices) ----------------------------------------

    std::set<std::string> nodeIDs;

    for( auto&& node : _nodes )
    {
      auto pair = nodeIDs.insert( node.id );
      if( !pair.second )
        throw std::runtime_error( "Duplicate node id '" + node.id + "'" );
    }

    // Lambda expression for creating a numerical ID out of a parsed ID. In
    // case non-numerical IDs are being used in the source file this Lambda
    // expression ensures that internal IDs always start with a zero.
    auto getID = [&nodeIDs] ( const std::string& id )
    {
      // Try to be smart: If the node ID can be converted into the
      // vertex type, we use the converted number instead.
      try
      {
        auto convertedID = std::stoll( id );
        return static_cast<VertexType>( convertedID );
      }
      catch( std::out_of_range& e )
      {
        throw;
      }
      catch( std::invalid_argument& )
      {
        return static_cast<VertexType>(
          std::distance( nodeIDs.begin(), nodeIDs.find( id ) )
        );
      }
    };

    std::vector<Simplex> simplices;
    simplices.reserve( _nodes.size() + _edges.size() );

    for( auto&& node : _nodes )
    {
      auto id = getID( node.id );

      if( node.dict.find( "weight" ) != node.dict.end() )
        simplices.push_back( Simplex( id, convert<DataType>( node.dict.at( "weight" ) ) ) );
      else if( node.dict.find( "value" ) != node.dict.end() )
        simplices.push_back( Simplex( id, convert<DataType>( node.dict.at( "value" ) ) ) );
      else
        simplices.push_back( Simplex( id ) );
    }

    // Create edges ----------------------------------------------------

    auto getSimplexByID = [&simplices] ( VertexType id )
    {
      auto position = std::find_if( simplices.begin(), simplices.end(),
                                    [&id] ( const Simplex& s )
                                    {
                                      return s.dimension() == 0 && s[0] == id;
                                    } );

      if( position != simplices.end() )
        return *position;
      else
        throw std::runtime_error( "Querying unknown simplex for edge creation" );
    };

    for( auto&& edge : _edges )
    {
      auto u = getID( edge.source );
      auto v = getID( edge.target );

      // No optional data attached; need to create weight based on node
      // weights, if those are available.
      if( edge.dict.find( "weight" ) == edge.dict.end() && edge.dict.find( "value" ) == edge.dict.end() )
      {
        // TODO: This is very slow and could be sped up by maintaining
        // the simplex ID somewhere else with faster access.
        auto uSimplex = getSimplexByID( u );
        auto vSimplex = getSimplexByID( v );

        // TODO: Permit the usage of other weight assignment strategies
        // here, for example by using a functor.
        auto data = std::max( uSimplex.data(), vSimplex.data() );

        simplices.push_back( Simplex( {u,v}, data ) );
      }

      // Use converted weight
      else if( edge.dict.find( "weight" ) != edge.dict.end() )
        simplices.push_back( Simplex( {u,v}, convert<DataType>( edge.dict.at( "weight" ) ) ) );
      else if( edge.dict.find( "value" ) != edge.dict.end() )
        simplices.push_back( Simplex( {u,v}, convert<DataType>( edge.dict.at( "value" ) ) ) );
    }

    _graph = graph;
    K      = SimplicialComplex( simplices.begin(), simplices.end() );
  }

  /**
    Retrieves a map of attribute values for each node. The attributes
    will be assigned to the node ID. Empty attributes signify that no
    such information is available.
  */

  std::map<std::string, std::string> getNodeAttribute( const std::string& attribute ) const
  {
    std::map<std::string, std::string> map;

    for( auto&& node : _nodes )
    {
      if( node.dict.find( attribute ) == node.dict.end() )
        map[ node.id ] = std::string();
      else
        map[ node.id ] = node.dict.at( attribute );
    }

    return map;
  }

private:

  /** Describes a parsed graph along with all of its attributes */
  struct Graph
  {
    std::map<std::string, std::string> dict; // all remaining attributes
  };

  /** Describes a parsed node along with all of its attributes */
  struct Node
  {
    std::string id;

    std::map<std::string, std::string> dict; // all remaining attributes
  };

  /** Describes a parsed edge along with all of its attributes */
  struct Edge
  {
    std::string source;
    std::string target;

    std::map<std::string, std::string> dict; // all remaining attributes
  };

  // Local storage -----------------------------------------------------
  //
  // Variables in this section contain the result of the last parsing
  // process. This is useful when clients are querying attributes.

  Graph _graph;

  std::vector<Node> _nodes;
  std::vector<Edge> _edges;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Added basic GML writing functionality<commit_after>#ifndef ALEPH_TOPOLOGY_IO_GML_HH__
#define ALEPH_TOPOLOGY_IO_GML_HH__

#include <fstream>
#include <map>
#include <set>
#include <regex>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

#include "utilities/String.hh"

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class GMLReader
  @brief Parses files in GML (Graph Modeling Language) format

  This is a simple reader for graphs in GML format. It suports a basic
  subset of the GML specification, viz. the specification of different
  attributes for nodes, as well as weight specifications for edges.

  Currently, the following attributes will be read:

  * \c id (for nodes)
  * \c label (for nodes)
  * \c source (for edges)
  * \c target (for edges)
  * \c weight (for edges)
*/

class GMLReader
{
public:

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  template <class SimplicialComplex> void operator()( std::ifstream& in, SimplicialComplex& K )
  {
    _nodes.clear();
    _edges.clear();

    using namespace aleph::utilities;

    using Simplex           = typename SimplicialComplex::ValueType;
    using DataType          = typename Simplex::DataType;
    using VertexType        = typename Simplex::VertexType;

    std::string line;
    std::set<std::string> levels     = { "graph", "node", "edge" };
    std::set<std::string> attributes = { "id", "label", "source", "target", "value", "weight" };

    auto isLevel = [&levels] ( const std::string& name )
    {
      return levels.find( name ) != levels.end();
    };

    auto isAttribute = [&attributes] ( const std::string& name )
    {
      return attributes.find( name ) != attributes.end();
    };

    // Specifies the current level the parser is in. May be either one
    // of the known levels above.
    std::stack<std::string> currentLevel;

    // Last level that was read by the parser. If an open bracket '[' is
    // identified, this will become the current level.
    std::string lastLevel;

    Graph graph;
    Node node;
    Edge edge;

    std::regex reAttribute = std::regex( "([[:alpha:]]+)[[:space:]]*.*" );
    std::regex reKeyValue  = std::regex( "([[:alpha:]]+)[[:space:]]+([[:alnum:]\\.]+)" );
    std::regex reLabel     = std::regex( "(label)[[:space:]]+\"([^\"]+)\"" );

    while( std::getline( in, line ) )
    {
      line = trim( line );

      // Skip comment lines. This is somewhat wasteful because I am
      // splitting the complete string even though I merely need to
      // know the first token.
      {
        auto tokens = split( line );
        if( tokens.empty() == false && ( tokens.front() == "comment" || tokens.front() == "Creator" ) )
          continue;
      }

      // Detecting a new level
      if( isLevel( line ) )
      {
        if( lastLevel.empty() )
          lastLevel = line;
        else
          throw std::runtime_error( "Encountered incorrectly-nested levels" );
      }

      // Opening a new level
      else if( line == "[" )
      {
        currentLevel.push( lastLevel );
        lastLevel = "";
      }

      // Closing a new level
      else if( line == "]" )
      {
        if( currentLevel.top() == "node" )
          _nodes.push_back( node );
        else if( currentLevel.top() == "edge" )
          _edges.push_back( edge );

        // Reset node and edge data structure to fill them again once
        // a new level is being encountered.
        node = {};
        edge = {};

        currentLevel.pop();
      }

      // Check for attributes
      else
      {
        std::smatch matches;

        auto* dict = currentLevel.top() == "node" ? &node.dict
                                                  : currentLevel.top() == "edge" ? &edge.dict
                                                                                : currentLevel.top() == "graph" ? &graph.dict
                                                                                : throw std::runtime_error( "Current level is unknown" );

        if( std::regex_match( line, matches, reAttribute ) )
        {
          auto name = matches[1];
          if( isAttribute( name ) )
          {
            // Special matching for labels
            if( name == "label" )
              std::regex_match( line, matches, reLabel );

            // Regular matching for all other attributes
            else
              std::regex_match( line, matches, reKeyValue );

            auto value = matches[2];

            if( name == "id" )
              node.id = value;
            else if( name == "source" )
              edge.source = value;
            else if( name == "target" )
              edge.target = value;

            // Just add it to the dictionary of optional values
            else
             dict->operator[]( name ) = value;
          }
          // Skip unknown attributes...
          else
          {
          }
        }
      }
    }

    // Creates nodes (vertices) ----------------------------------------

    std::set<std::string> nodeIDs;

    for( auto&& node : _nodes )
    {
      auto pair = nodeIDs.insert( node.id );
      if( !pair.second )
        throw std::runtime_error( "Duplicate node id '" + node.id + "'" );
    }

    // Lambda expression for creating a numerical ID out of a parsed ID. In
    // case non-numerical IDs are being used in the source file this Lambda
    // expression ensures that internal IDs always start with a zero.
    auto getID = [&nodeIDs] ( const std::string& id )
    {
      // Try to be smart: If the node ID can be converted into the
      // vertex type, we use the converted number instead.
      try
      {
        auto convertedID = std::stoll( id );
        return static_cast<VertexType>( convertedID );
      }
      catch( std::out_of_range& e )
      {
        throw;
      }
      catch( std::invalid_argument& )
      {
        return static_cast<VertexType>(
          std::distance( nodeIDs.begin(), nodeIDs.find( id ) )
        );
      }
    };

    std::vector<Simplex> simplices;
    simplices.reserve( _nodes.size() + _edges.size() );

    for( auto&& node : _nodes )
    {
      auto id = getID( node.id );

      if( node.dict.find( "weight" ) != node.dict.end() )
        simplices.push_back( Simplex( id, convert<DataType>( node.dict.at( "weight" ) ) ) );
      else if( node.dict.find( "value" ) != node.dict.end() )
        simplices.push_back( Simplex( id, convert<DataType>( node.dict.at( "value" ) ) ) );
      else
        simplices.push_back( Simplex( id ) );
    }

    // Create edges ----------------------------------------------------

    auto getSimplexByID = [&simplices] ( VertexType id )
    {
      auto position = std::find_if( simplices.begin(), simplices.end(),
                                    [&id] ( const Simplex& s )
                                    {
                                      return s.dimension() == 0 && s[0] == id;
                                    } );

      if( position != simplices.end() )
        return *position;
      else
        throw std::runtime_error( "Querying unknown simplex for edge creation" );
    };

    for( auto&& edge : _edges )
    {
      auto u = getID( edge.source );
      auto v = getID( edge.target );

      // No optional data attached; need to create weight based on node
      // weights, if those are available.
      if( edge.dict.find( "weight" ) == edge.dict.end() && edge.dict.find( "value" ) == edge.dict.end() )
      {
        // TODO: This is very slow and could be sped up by maintaining
        // the simplex ID somewhere else with faster access.
        auto uSimplex = getSimplexByID( u );
        auto vSimplex = getSimplexByID( v );

        // TODO: Permit the usage of other weight assignment strategies
        // here, for example by using a functor.
        auto data = std::max( uSimplex.data(), vSimplex.data() );

        simplices.push_back( Simplex( {u,v}, data ) );
      }

      // Use converted weight
      else if( edge.dict.find( "weight" ) != edge.dict.end() )
        simplices.push_back( Simplex( {u,v}, convert<DataType>( edge.dict.at( "weight" ) ) ) );
      else if( edge.dict.find( "value" ) != edge.dict.end() )
        simplices.push_back( Simplex( {u,v}, convert<DataType>( edge.dict.at( "value" ) ) ) );
    }

    _graph = graph;
    K      = SimplicialComplex( simplices.begin(), simplices.end() );
  }

  /**
    Retrieves a map of attribute values for each node. The attributes
    will be assigned to the node ID. Empty attributes signify that no
    such information is available.
  */

  std::map<std::string, std::string> getNodeAttribute( const std::string& attribute ) const
  {
    std::map<std::string, std::string> map;

    for( auto&& node : _nodes )
    {
      if( node.dict.find( attribute ) == node.dict.end() )
        map[ node.id ] = std::string();
      else
        map[ node.id ] = node.dict.at( attribute );
    }

    return map;
  }

private:

  /** Describes a parsed graph along with all of its attributes */
  struct Graph
  {
    std::map<std::string, std::string> dict; // all remaining attributes
  };

  /** Describes a parsed node along with all of its attributes */
  struct Node
  {
    std::string id;

    std::map<std::string, std::string> dict; // all remaining attributes
  };

  /** Describes a parsed edge along with all of its attributes */
  struct Edge
  {
    std::string source;
    std::string target;

    std::map<std::string, std::string> dict; // all remaining attributes
  };

  // Local storage -----------------------------------------------------
  //
  // Variables in this section contain the result of the last parsing
  // process. This is useful when clients are querying attributes.

  Graph _graph;

  std::vector<Node> _nodes;
  std::vector<Edge> _edges;
};

/**
  @class GMLWriter
  @brief Writes files in GML (Graph Modeling Language) format

  This is a simple writer for graphs in GML format. It suports a basic
  subset of the GML specification, viz. the specification of different
  attributes for nodes, as well as weight specifications for edges.

  Given a simplicial complex, it will store it as a weighted graph.

  Currently, the following attributes will be written:

  * \c id (for nodes)
  * \c source (for edges)
  * \c target (for edges)
  * \c weight (for edges)
*/

class GMLWriter
{
public:

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ofstream out( filename );
    if( !out )
      throw std::runtime_error( "Unable to open output file" );

    this->operator()( out, K );
  }

  template <class SimplicialComplex> void operator()( std::ostream& out, SimplicialComplex& K )
  {
    std::ostringstream streamNodes;
    std::ostringstream streamEdges;

    for( auto&& simplex : K )
    {
      if( simplex.dimension() == 0 )
      {
        streamNodes << "  node [\n"
                    << "    id " << *simplex.begin() << "\n"
                    << "  ]\n";
      }
      else if( simplex.dimension() == 1 )
      {
        auto u = *( simplex.begin()     );
        auto v = *( simplex.begin() + 1 );

        streamEdges << "  edge [\n"
                    << "    source " << u << "\n"
                    << "    target " << v << "\n"
                    << "    weight " << simplex.data() << "\n"
                    << "  ]\n";
      }
    }

    out << "graph [\n"
        << "  directed 0\n"
        << streamNodes.str() << "\n"
        << streamEdges.str() << "\n"
        << "]\n";
  }
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>//===-- sanitizer_vector_test.cc ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of *Sanitizer runtime.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_vector.h"
#include "gtest/gtest.h"

namespace __sanitizer {

TEST(Vector, Basic) {
  Vector<int> v;
  EXPECT_EQ(v.Size(), (uptr)0);
  v.PushBack(42);
  EXPECT_EQ(v.Size(), (uptr)1);
  EXPECT_EQ(v[0], 42);
  v.PushBack(43);
  EXPECT_EQ(v.Size(), (uptr)2);
  EXPECT_EQ(v[0], 42);
  EXPECT_EQ(v[1], 43);
}

TEST(Vector, Stride) {
  Vector<int> v;
  for (int i = 0; i < 1000; i++) {
    v.PushBack(i);
    EXPECT_EQ(v.Size(), (uptr)(i + 1));
    EXPECT_EQ(v[i], i);
  }
  for (int i = 0; i < 1000; i++) {
    EXPECT_EQ(v[i], i);
  }
}

}  // namespace __sanitizer
<commit_msg>[sanitizer] Replace cast with unsigned literals in tests<commit_after>//===-- sanitizer_vector_test.cc ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of *Sanitizer runtime.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_vector.h"
#include "gtest/gtest.h"

namespace __sanitizer {

TEST(Vector, Basic) {
  Vector<int> v;
  EXPECT_EQ(v.Size(), 0u);
  v.PushBack(42);
  EXPECT_EQ(v.Size(), 1u);
  EXPECT_EQ(v[0], 42);
  v.PushBack(43);
  EXPECT_EQ(v.Size(), 2u);
  EXPECT_EQ(v[0], 42);
  EXPECT_EQ(v[1], 43);
}

TEST(Vector, Stride) {
  Vector<int> v;
  for (int i = 0; i < 1000; i++) {
    v.PushBack(i);
    EXPECT_EQ(v.Size(), i + 1u);
    EXPECT_EQ(v[i], i);
  }
  for (int i = 0; i < 1000; i++) {
    EXPECT_EQ(v[i], i);
  }
}

}  // namespace __sanitizer
<|endoftext|>


<commit_before>#include "tests/ffi/tests.h"
#include "tests/ffi/lib.rs.h"
#include <cstring>
#include <numeric>
#include <stdexcept>

extern "C" void cxx_test_suite_set_correct() noexcept;
extern "C" tests::R *cxx_test_suite_get_box() noexcept;
extern "C" bool cxx_test_suite_r_is_correct(const tests::R *) noexcept;

namespace tests {

static constexpr char SLICE_DATA[] = "2020";

C::C(size_t n) : n(n) {}

size_t C::get() const { return this->n; }

size_t C::get2() const { return this->n; }

size_t C::set(size_t n) {
  this->n = n;
  return this->n;
}

size_t C::set2(size_t n) {
  this->n = n;
  return this->n;
}

size_t C::set_succeed(size_t n) { return this->set2(n); }

size_t C::get_fail() { throw std::runtime_error("unimplemented"); }

const std::vector<uint8_t> &C::get_v() const { return this->v; }

size_t c_return_primitive() { return 2020; }

Shared c_return_shared() { return Shared{2020}; }

rust::Box<R> c_return_box() {
  return rust::Box<R>::from_raw(cxx_test_suite_get_box());
}

std::unique_ptr<C> c_return_unique_ptr() {
  return std::unique_ptr<C>(new C{2020});
}

const size_t &c_return_ref(const Shared &shared) { return shared.z; }

rust::Str c_return_str(const Shared &shared) {
  (void)shared;
  return "2020";
}

rust::Slice<uint8_t> c_return_sliceu8(const Shared &shared) {
  (void)shared;
  return rust::Slice<uint8_t>(reinterpret_cast<const uint8_t *>(SLICE_DATA),
                              sizeof(SLICE_DATA));
}

rust::String c_return_rust_string() { return "2020"; }

std::unique_ptr<std::string> c_return_unique_ptr_string() {
  return std::unique_ptr<std::string>(new std::string("2020"));
}

std::unique_ptr<std::vector<uint8_t>> c_return_unique_ptr_vector_u8() {
  auto vec = std::unique_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
  vec->push_back(86);
  vec->push_back(75);
  vec->push_back(30);
  vec->push_back(9);
  return vec;
}

std::unique_ptr<std::vector<double>> c_return_unique_ptr_vector_f64() {
  auto vec = std::unique_ptr<std::vector<double>>(new std::vector<double>());
  vec->push_back(86.0);
  vec->push_back(75.0);
  vec->push_back(30.0);
  vec->push_back(9.5);
  return vec;
}

std::unique_ptr<std::vector<Shared>> c_return_unique_ptr_vector_shared() {
  auto vec = std::unique_ptr<std::vector<Shared>>(new std::vector<Shared>());
  vec->push_back(Shared{1010});
  vec->push_back(Shared{1011});
  return vec;
}

std::unique_ptr<std::vector<C>> c_return_unique_ptr_vector_opaque() {
  return std::unique_ptr<std::vector<C>>(new std::vector<C>());
}

const std::vector<uint8_t> &c_return_ref_vector(const C &c) {
  return c.get_v();
}

rust::Vec<uint8_t> c_return_rust_vec() {
  throw std::runtime_error("unimplemented");
}

const rust::Vec<uint8_t> &c_return_ref_rust_vec(const C &c) {
  (void)c;
  throw std::runtime_error("unimplemented");
}

size_t c_return_identity(size_t n) { return n; }

size_t c_return_sum(size_t n1, size_t n2) { return n1 + n2; }

Enum c_return_enum(uint16_t n) {
  if (n <= static_cast<uint16_t>(Enum::AVal)) {
    return Enum::AVal;
  } else if (n <= static_cast<uint16_t>(Enum::BVal)) {
    return Enum::BVal;
  } else {
    return Enum::CVal;
  }
}

void c_take_primitive(size_t n) {
  if (n == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_shared(Shared shared) {
  if (shared.z == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_box(rust::Box<R> r) {
  if (cxx_test_suite_r_is_correct(&*r)) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr(std::unique_ptr<C> c) {
  if (c->get() == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_r(const R &r) {
  if (cxx_test_suite_r_is_correct(&r)) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_c(const C &c) {
  if (c.get() == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_str(rust::Str s) {
  if (std::string(s) == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_sliceu8(rust::Slice<uint8_t> s) {
  if (std::string(reinterpret_cast<const char *>(s.data()), s.size()) ==
      "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_string(rust::String s) {
  if (std::string(s) == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_string(std::unique_ptr<std::string> s) {
  if (*s == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v) {
  if (v->size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_f64(std::unique_ptr<std::vector<double>> v) {
  if (v->size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_shared(std::unique_ptr<std::vector<Shared>> v) {
  if (v->size() == 2) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_vector(const std::vector<uint8_t> &v) {
  if (v.size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_vec(rust::Vec<uint8_t> v) { c_take_ref_rust_vec(v); }

void c_take_rust_vec_shared(rust::Vec<Shared> v) {
  uint32_t sum = 0;
  for (auto i : v) {
    sum += i.z;
  }
  if (sum == 2021) {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_vec_shared_forward_iterator(rust::Vec<Shared> v) {
  // Exercise requirements of ForwardIterator
  // https://en.cppreference.com/w/cpp/named_req/ForwardIterator
  uint32_t sum = 0;
  for (auto it = v.begin(), it_end = v.end(); it != it_end; it++) {
    sum += it->z;
  }
  if (sum == 2021) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_rust_vec(const rust::Vec<uint8_t> &v) {
  uint8_t sum = std::accumulate(v.begin(), v.end(), 0);
  if (sum == 200) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_rust_vec_copy(const rust::Vec<uint8_t> &v) {
  // The std::copy() will make sure rust::Vec<>::const_iterator satisfies the
  // requirements for std::iterator_traits.
  // https://en.cppreference.com/w/cpp/iterator/iterator_traits
  std::vector<uint8_t> stdv;
  std::copy(v.begin(), v.end(), std::back_inserter(stdv));
  uint8_t sum = std::accumulate(stdv.begin(), stdv.end(), 0);
  if (sum == 200) {
    cxx_test_suite_set_correct();
  }
}

/*
// https://github.com/dtolnay/cxx/issues/232
void c_take_callback(rust::Fn<size_t(rust::String)> callback) {
  callback("2020");
}
*/

void c_take_enum(Enum e) {
  if (e == Enum::AVal) {
    cxx_test_suite_set_correct();
  }
}

void c_try_return_void() {}

size_t c_try_return_primitive() { return 2020; }

size_t c_fail_return_primitive() { throw std::logic_error("logic error"); }

rust::Box<R> c_try_return_box() { return c_return_box(); }

const rust::String &c_try_return_ref(const rust::String &s) { return s; }

rust::Str c_try_return_str(rust::Str s) { return s; }

rust::Slice<uint8_t> c_try_return_sliceu8(rust::Slice<uint8_t> s) { return s; }

rust::String c_try_return_rust_string() { return c_return_rust_string(); }

std::unique_ptr<std::string> c_try_return_unique_ptr_string() {
  return c_return_unique_ptr_string();
}

rust::Vec<uint8_t> c_try_return_rust_vec() {
  throw std::runtime_error("unimplemented");
}

const rust::Vec<uint8_t> &c_try_return_ref_rust_vec(const C &c) {
  (void)c;
  throw std::runtime_error("unimplemented");
}

extern "C" C *cxx_test_suite_get_unique_ptr() noexcept {
  return std::unique_ptr<C>(new C{2020}).release();
}

extern "C" std::string *cxx_test_suite_get_unique_ptr_string() noexcept {
  return std::unique_ptr<std::string>(new std::string("2020")).release();
}

extern "C" const char *cxx_run_test() noexcept {
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define ASSERT(x)                                                              \
  do {                                                                         \
    if (!(x)) {                                                                \
      return "Assertion failed: `" #x "`, " __FILE__ ":" TOSTRING(__LINE__);   \
    }                                                                          \
  } while (false)

  ASSERT(r_return_primitive() == 2020);
  ASSERT(r_return_shared().z == 2020);
  ASSERT(cxx_test_suite_r_is_correct(&*r_return_box()));
  ASSERT(r_return_unique_ptr()->get() == 2020);
  ASSERT(r_return_ref(Shared{2020}) == 2020);
  ASSERT(std::string(r_return_str(Shared{2020})) == "2020");
  ASSERT(std::string(r_return_rust_string()) == "2020");
  ASSERT(*r_return_unique_ptr_string() == "2020");
  ASSERT(r_return_identity(2020) == 2020);
  ASSERT(r_return_sum(2020, 1) == 2021);
  ASSERT(r_return_enum(0) == Enum::AVal);
  ASSERT(r_return_enum(1) == Enum::BVal);
  ASSERT(r_return_enum(2021) == Enum::CVal);

  r_take_primitive(2020);
  r_take_shared(Shared{2020});
  r_take_unique_ptr(std::unique_ptr<C>(new C{2020}));
  r_take_ref_c(C{2020});
  r_take_str(rust::Str("2020"));
  r_take_sliceu8(rust::Slice<uint8_t>(
      reinterpret_cast<const uint8_t *>(SLICE_DATA), sizeof(SLICE_DATA)));
  r_take_rust_string(rust::String("2020"));
  r_take_unique_ptr_string(
      std::unique_ptr<std::string>(new std::string("2020")));
  r_take_enum(Enum::AVal);

  ASSERT(r_try_return_primitive() == 2020);
  try {
    r_fail_return_primitive();
    ASSERT(false);
  } catch (const rust::Error &e) {
    ASSERT(std::strcmp(e.what(), "rust error") == 0);
  }

  auto r2 = r_return_r2(2020);
  ASSERT(r2->get() == 2020);
  ASSERT(r2->set(2021) == 2021);
  ASSERT(r2->get() == 2021);
  ASSERT(r2->set(2020) == 2020);
  ASSERT(r2->get() == 2020);

  cxx_test_suite_set_correct();
  return nullptr;
}

} // namespace tests
<commit_msg>Add include required for back_inserter<commit_after>#include "tests/ffi/tests.h"
#include "tests/ffi/lib.rs.h"
#include <cstring>
#include <iterator>
#include <numeric>
#include <stdexcept>

extern "C" void cxx_test_suite_set_correct() noexcept;
extern "C" tests::R *cxx_test_suite_get_box() noexcept;
extern "C" bool cxx_test_suite_r_is_correct(const tests::R *) noexcept;

namespace tests {

static constexpr char SLICE_DATA[] = "2020";

C::C(size_t n) : n(n) {}

size_t C::get() const { return this->n; }

size_t C::get2() const { return this->n; }

size_t C::set(size_t n) {
  this->n = n;
  return this->n;
}

size_t C::set2(size_t n) {
  this->n = n;
  return this->n;
}

size_t C::set_succeed(size_t n) { return this->set2(n); }

size_t C::get_fail() { throw std::runtime_error("unimplemented"); }

const std::vector<uint8_t> &C::get_v() const { return this->v; }

size_t c_return_primitive() { return 2020; }

Shared c_return_shared() { return Shared{2020}; }

rust::Box<R> c_return_box() {
  return rust::Box<R>::from_raw(cxx_test_suite_get_box());
}

std::unique_ptr<C> c_return_unique_ptr() {
  return std::unique_ptr<C>(new C{2020});
}

const size_t &c_return_ref(const Shared &shared) { return shared.z; }

rust::Str c_return_str(const Shared &shared) {
  (void)shared;
  return "2020";
}

rust::Slice<uint8_t> c_return_sliceu8(const Shared &shared) {
  (void)shared;
  return rust::Slice<uint8_t>(reinterpret_cast<const uint8_t *>(SLICE_DATA),
                              sizeof(SLICE_DATA));
}

rust::String c_return_rust_string() { return "2020"; }

std::unique_ptr<std::string> c_return_unique_ptr_string() {
  return std::unique_ptr<std::string>(new std::string("2020"));
}

std::unique_ptr<std::vector<uint8_t>> c_return_unique_ptr_vector_u8() {
  auto vec = std::unique_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
  vec->push_back(86);
  vec->push_back(75);
  vec->push_back(30);
  vec->push_back(9);
  return vec;
}

std::unique_ptr<std::vector<double>> c_return_unique_ptr_vector_f64() {
  auto vec = std::unique_ptr<std::vector<double>>(new std::vector<double>());
  vec->push_back(86.0);
  vec->push_back(75.0);
  vec->push_back(30.0);
  vec->push_back(9.5);
  return vec;
}

std::unique_ptr<std::vector<Shared>> c_return_unique_ptr_vector_shared() {
  auto vec = std::unique_ptr<std::vector<Shared>>(new std::vector<Shared>());
  vec->push_back(Shared{1010});
  vec->push_back(Shared{1011});
  return vec;
}

std::unique_ptr<std::vector<C>> c_return_unique_ptr_vector_opaque() {
  return std::unique_ptr<std::vector<C>>(new std::vector<C>());
}

const std::vector<uint8_t> &c_return_ref_vector(const C &c) {
  return c.get_v();
}

rust::Vec<uint8_t> c_return_rust_vec() {
  throw std::runtime_error("unimplemented");
}

const rust::Vec<uint8_t> &c_return_ref_rust_vec(const C &c) {
  (void)c;
  throw std::runtime_error("unimplemented");
}

size_t c_return_identity(size_t n) { return n; }

size_t c_return_sum(size_t n1, size_t n2) { return n1 + n2; }

Enum c_return_enum(uint16_t n) {
  if (n <= static_cast<uint16_t>(Enum::AVal)) {
    return Enum::AVal;
  } else if (n <= static_cast<uint16_t>(Enum::BVal)) {
    return Enum::BVal;
  } else {
    return Enum::CVal;
  }
}

void c_take_primitive(size_t n) {
  if (n == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_shared(Shared shared) {
  if (shared.z == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_box(rust::Box<R> r) {
  if (cxx_test_suite_r_is_correct(&*r)) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr(std::unique_ptr<C> c) {
  if (c->get() == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_r(const R &r) {
  if (cxx_test_suite_r_is_correct(&r)) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_c(const C &c) {
  if (c.get() == 2020) {
    cxx_test_suite_set_correct();
  }
}

void c_take_str(rust::Str s) {
  if (std::string(s) == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_sliceu8(rust::Slice<uint8_t> s) {
  if (std::string(reinterpret_cast<const char *>(s.data()), s.size()) ==
      "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_string(rust::String s) {
  if (std::string(s) == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_string(std::unique_ptr<std::string> s) {
  if (*s == "2020") {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v) {
  if (v->size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_f64(std::unique_ptr<std::vector<double>> v) {
  if (v->size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_unique_ptr_vector_shared(std::unique_ptr<std::vector<Shared>> v) {
  if (v->size() == 2) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_vector(const std::vector<uint8_t> &v) {
  if (v.size() == 4) {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_vec(rust::Vec<uint8_t> v) { c_take_ref_rust_vec(v); }

void c_take_rust_vec_shared(rust::Vec<Shared> v) {
  uint32_t sum = 0;
  for (auto i : v) {
    sum += i.z;
  }
  if (sum == 2021) {
    cxx_test_suite_set_correct();
  }
}

void c_take_rust_vec_shared_forward_iterator(rust::Vec<Shared> v) {
  // Exercise requirements of ForwardIterator
  // https://en.cppreference.com/w/cpp/named_req/ForwardIterator
  uint32_t sum = 0;
  for (auto it = v.begin(), it_end = v.end(); it != it_end; it++) {
    sum += it->z;
  }
  if (sum == 2021) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_rust_vec(const rust::Vec<uint8_t> &v) {
  uint8_t sum = std::accumulate(v.begin(), v.end(), 0);
  if (sum == 200) {
    cxx_test_suite_set_correct();
  }
}

void c_take_ref_rust_vec_copy(const rust::Vec<uint8_t> &v) {
  // The std::copy() will make sure rust::Vec<>::const_iterator satisfies the
  // requirements for std::iterator_traits.
  // https://en.cppreference.com/w/cpp/iterator/iterator_traits
  std::vector<uint8_t> stdv;
  std::copy(v.begin(), v.end(), std::back_inserter(stdv));
  uint8_t sum = std::accumulate(stdv.begin(), stdv.end(), 0);
  if (sum == 200) {
    cxx_test_suite_set_correct();
  }
}

/*
// https://github.com/dtolnay/cxx/issues/232
void c_take_callback(rust::Fn<size_t(rust::String)> callback) {
  callback("2020");
}
*/

void c_take_enum(Enum e) {
  if (e == Enum::AVal) {
    cxx_test_suite_set_correct();
  }
}

void c_try_return_void() {}

size_t c_try_return_primitive() { return 2020; }

size_t c_fail_return_primitive() { throw std::logic_error("logic error"); }

rust::Box<R> c_try_return_box() { return c_return_box(); }

const rust::String &c_try_return_ref(const rust::String &s) { return s; }

rust::Str c_try_return_str(rust::Str s) { return s; }

rust::Slice<uint8_t> c_try_return_sliceu8(rust::Slice<uint8_t> s) { return s; }

rust::String c_try_return_rust_string() { return c_return_rust_string(); }

std::unique_ptr<std::string> c_try_return_unique_ptr_string() {
  return c_return_unique_ptr_string();
}

rust::Vec<uint8_t> c_try_return_rust_vec() {
  throw std::runtime_error("unimplemented");
}

const rust::Vec<uint8_t> &c_try_return_ref_rust_vec(const C &c) {
  (void)c;
  throw std::runtime_error("unimplemented");
}

extern "C" C *cxx_test_suite_get_unique_ptr() noexcept {
  return std::unique_ptr<C>(new C{2020}).release();
}

extern "C" std::string *cxx_test_suite_get_unique_ptr_string() noexcept {
  return std::unique_ptr<std::string>(new std::string("2020")).release();
}

extern "C" const char *cxx_run_test() noexcept {
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define ASSERT(x)                                                              \
  do {                                                                         \
    if (!(x)) {                                                                \
      return "Assertion failed: `" #x "`, " __FILE__ ":" TOSTRING(__LINE__);   \
    }                                                                          \
  } while (false)

  ASSERT(r_return_primitive() == 2020);
  ASSERT(r_return_shared().z == 2020);
  ASSERT(cxx_test_suite_r_is_correct(&*r_return_box()));
  ASSERT(r_return_unique_ptr()->get() == 2020);
  ASSERT(r_return_ref(Shared{2020}) == 2020);
  ASSERT(std::string(r_return_str(Shared{2020})) == "2020");
  ASSERT(std::string(r_return_rust_string()) == "2020");
  ASSERT(*r_return_unique_ptr_string() == "2020");
  ASSERT(r_return_identity(2020) == 2020);
  ASSERT(r_return_sum(2020, 1) == 2021);
  ASSERT(r_return_enum(0) == Enum::AVal);
  ASSERT(r_return_enum(1) == Enum::BVal);
  ASSERT(r_return_enum(2021) == Enum::CVal);

  r_take_primitive(2020);
  r_take_shared(Shared{2020});
  r_take_unique_ptr(std::unique_ptr<C>(new C{2020}));
  r_take_ref_c(C{2020});
  r_take_str(rust::Str("2020"));
  r_take_sliceu8(rust::Slice<uint8_t>(
      reinterpret_cast<const uint8_t *>(SLICE_DATA), sizeof(SLICE_DATA)));
  r_take_rust_string(rust::String("2020"));
  r_take_unique_ptr_string(
      std::unique_ptr<std::string>(new std::string("2020")));
  r_take_enum(Enum::AVal);

  ASSERT(r_try_return_primitive() == 2020);
  try {
    r_fail_return_primitive();
    ASSERT(false);
  } catch (const rust::Error &e) {
    ASSERT(std::strcmp(e.what(), "rust error") == 0);
  }

  auto r2 = r_return_r2(2020);
  ASSERT(r2->get() == 2020);
  ASSERT(r2->set(2021) == 2021);
  ASSERT(r2->get() == 2021);
  ASSERT(r2->set(2020) == 2020);
  ASSERT(r2->get() == 2020);

  cxx_test_suite_set_correct();
  return nullptr;
}

} // namespace tests
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 wisol technologie GmbH
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * \author    Michael Egli
 * \copyright wisol technologie GmbH
 * \date      18-Dec-2014
 *
 * \file fsm_test.cpp
 * Test definitions for the state machine implementation.
 */

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <array>
#include "../fsm.h"

TEST_CASE("Test Initialization")
{
	FSM::Fsm fsm;
	REQUIRE(fsm.execute('a') == FSM::Fsm_NotInitialized);
}

TEST_CASE("Test initial and final pseudo states")
{
	FSM::Fsm fsm;
	std::array<FSM::Trans,1> transitions = {{
			{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();

	SECTION("Test initial pseudo state") {
		REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
		REQUIRE(fsm.is_initial() == true);
		REQUIRE(fsm.is_final() == false);
	}

	SECTION("Test initial pseudo state") {
		fsm.execute('a');
		REQUIRE(fsm.state() == (int)FSM::Fsm_Final);
		REQUIRE(fsm.is_initial() == false);
		REQUIRE(fsm.is_final() == true);
	}
}

TEST_CASE("Test missing trigger")
{
	FSM::Fsm fsm;
	std::array<FSM::Trans,1> transitions = {{
			{FSM::Fsm_Initial, FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_NoMatchingTrigger);
}

TEST_CASE("Test guards")
{
	SECTION("Test false guard") {
		FSM::Fsm fsm;
		std::array<FSM::Trans,1> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return false;}, nullptr},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that the transition to final is not taken (because of the guard).
		REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
	}

	SECTION("Test true guard") {
		FSM::Fsm fsm;
		std::array<FSM::Trans,1> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return true;}, nullptr},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that the transition to final is taken (because of the guard).
		REQUIRE(fsm.state() == (int)FSM::Fsm_Final);
	}

	SECTION("Test same action with different guards") {
		int count = 0;
		FSM::Fsm fsm;
		std::array<FSM::Trans,2> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return false;}, [&count]{count++;}},
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return true; }, [&count]{count = 10;}},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that action2 was taken (because of the guard).
		REQUIRE(count == 10);
	}
}

TEST_CASE("Test Transitions")
{
	SECTION("Test multiple matching transitions") {
		int count = 0;
		const int stateA = 1;
		FSM::Fsm fsm;
		std::array<FSM::Trans,3> transitions = {{
				{FSM::Fsm_Initial, stateA        , 'a', nullptr, [&count]{count++;}},
				{stateA          , stateA        , 'a', nullptr, [&count]{count++;}},
				{stateA          , FSM::Fsm_Final, 'a', nullptr, [&count]{count++;}},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// Ensure that only one action has executed.
		REQUIRE(count == 1);
	}
}

TEST_CASE("Test state machine reset")
{
	int action_count = 0;
	const int stateA = 1;
	FSM::Fsm fsm;
	std::array<FSM::Trans,2> transitions = {{
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
	REQUIRE(fsm.state() == stateA);
	fsm.reset();
	REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
	REQUIRE(fsm.execute('a') == FSM::Fsm_NotInitialized);
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
	REQUIRE(fsm.execute('b') == FSM::Fsm_Success);
	REQUIRE(fsm.is_final() == true);
}

TEST_CASE("Test debug function")
{
	int action_count = 0;
	const int stateA = 1;
	FSM::Fsm fsm;
	std::array<FSM::Trans,2> transitions = {{
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();

	SECTION("Test enable debugging function.") {
		int dbg_from = 0;
		int dbg_to = 0;
		char dbg_tr = 0;
		fsm.add_debug_fn([&dbg_from, &dbg_to, &dbg_tr](int from, int to, char tr) { dbg_from = from; dbg_to = to; dbg_tr = tr; });
		fsm.execute('a');
		REQUIRE(dbg_from == FSM::Fsm_Initial);
		REQUIRE(dbg_to == stateA);
		REQUIRE(dbg_tr == 'a');
	}

	SECTION("Test disable debugging function.") {
		int dbg_from = 0;
		int dbg_to = 0;
		char dbg_tr = 0;
		fsm.reset();
		fsm.add_debug_fn(nullptr);
		REQUIRE(dbg_from == 0);
		REQUIRE(dbg_to == 0);
		REQUIRE(dbg_tr == 0);
	}
}

<commit_msg>Add tests for overloaded `add_transitions()` functions.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 wisol technologie GmbH
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * \author    Michael Egli
 * \copyright wisol technologie GmbH
 * \date      18-Dec-2014
 *
 * \file fsm_test.cpp
 * Test definitions for the state machine implementation.
 */

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <array>
#include <vector>
#include "../fsm.h"

TEST_CASE("Test Initialization")
{
	FSM::Fsm fsm;
	REQUIRE(fsm.execute('a') == FSM::Fsm_NotInitialized);
}

TEST_CASE("Test initial and final pseudo states")
{
	FSM::Fsm fsm;
	std::array<FSM::Trans,1> transitions = {{
			{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();

	SECTION("Test initial pseudo state") {
		REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
		REQUIRE(fsm.is_initial() == true);
		REQUIRE(fsm.is_final() == false);
	}

	SECTION("Test initial pseudo state") {
		fsm.execute('a');
		REQUIRE(fsm.state() == (int)FSM::Fsm_Final);
		REQUIRE(fsm.is_initial() == false);
		REQUIRE(fsm.is_final() == true);
	}
}

TEST_CASE("Test missing trigger")
{
	FSM::Fsm fsm;
	std::array<FSM::Trans,1> transitions = {{
			{FSM::Fsm_Initial, FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_NoMatchingTrigger);
}

TEST_CASE("Test guards")
{
	SECTION("Test false guard") {
		FSM::Fsm fsm;
		std::array<FSM::Trans,1> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return false;}, nullptr},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that the transition to final is not taken (because of the guard).
		REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
	}

	SECTION("Test true guard") {
		FSM::Fsm fsm;
		std::array<FSM::Trans,1> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return true;}, nullptr},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that the transition to final is taken (because of the guard).
		REQUIRE(fsm.state() == (int)FSM::Fsm_Final);
	}

	SECTION("Test same action with different guards") {
		int count = 0;
		FSM::Fsm fsm;
		std::array<FSM::Trans,2> transitions = {{
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return false;}, [&count]{count++;}},
				{FSM::Fsm_Initial, FSM::Fsm_Final, 'a', []{return true; }, [&count]{count = 10;}},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// ensure that action2 was taken (because of the guard).
		REQUIRE(count == 10);
	}
}

TEST_CASE("Test Transitions")
{
	SECTION("Test multiple matching transitions") {
		int count = 0;
		const int stateA = 1;
		FSM::Fsm fsm;
		std::array<FSM::Trans,3> transitions = {{
				{FSM::Fsm_Initial, stateA        , 'a', nullptr, [&count]{count++;}},
				{stateA          , stateA        , 'a', nullptr, [&count]{count++;}},
				{stateA          , FSM::Fsm_Final, 'a', nullptr, [&count]{count++;}},
		}};
		fsm.add_transitions(transitions.begin(), transitions.end());
		fsm.init();
		REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
		// Ensure that only one action has executed.
		REQUIRE(count == 1);
	}
}

TEST_CASE("Test state machine reset")
{
	int action_count = 0;
	const int stateA = 1;
	FSM::Fsm fsm;
	std::array<FSM::Trans,2> transitions = {{
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
	REQUIRE(fsm.state() == stateA);
	fsm.reset();
	REQUIRE(fsm.state() == (int)FSM::Fsm_Initial);
	REQUIRE(fsm.execute('a') == FSM::Fsm_NotInitialized);
	fsm.init();
	REQUIRE(fsm.execute('a') == FSM::Fsm_Success);
	REQUIRE(fsm.execute('b') == FSM::Fsm_Success);
	REQUIRE(fsm.is_final() == true);
}

TEST_CASE("Test debug function")
{
	int action_count = 0;
	const int stateA = 1;
	FSM::Fsm fsm;
	std::array<FSM::Trans,2> transitions = {{
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
	}};
	fsm.add_transitions(transitions.begin(), transitions.end());
	fsm.init();

	SECTION("Test enable debugging function.") {
		int dbg_from = 0;
		int dbg_to = 0;
		char dbg_tr = 0;
		fsm.add_debug_fn([&dbg_from, &dbg_to, &dbg_tr](int from, int to, char tr) { dbg_from = from; dbg_to = to; dbg_tr = tr; });
		fsm.execute('a');
		REQUIRE(dbg_from == FSM::Fsm_Initial);
		REQUIRE(dbg_to == stateA);
		REQUIRE(dbg_tr == 'a');
	}

	SECTION("Test disable debugging function.") {
		int dbg_from = 0;
		int dbg_to = 0;
		char dbg_tr = 0;
		fsm.reset();
		fsm.add_debug_fn(nullptr);
		REQUIRE(dbg_from == 0);
		REQUIRE(dbg_to == 0);
		REQUIRE(dbg_tr == 0);
	}
}

TEST_CASE("Test single argument add_transitions function")
{
	FSM::Fsm fsm;
	const int stateA = 1;

	SECTION("Test vector") {
		std::vector<FSM::Trans> v = {
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
		};
		fsm.add_transitions(v);
		fsm.init();
		fsm.execute('a');
		fsm.execute('b');
		REQUIRE(fsm.state() == FSM::Fsm_Final);
	}

	SECTION("Test initializer list") {
		fsm.add_transitions({
			{FSM::Fsm_Initial, stateA        , 'a', nullptr, nullptr},
			{stateA          , FSM::Fsm_Final, 'b', nullptr, nullptr},
			});
		fsm.init();
		fsm.execute('a');
		fsm.execute('b');
		REQUIRE(fsm.state() == FSM::Fsm_Final);
	}

}

<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <gtest/gtest.h>

#include "utils/util.hpp"

class test_obj {
private:
  int a;
public:
  test_obj(int a): a(a) {}
  int getInt() {return a;}
  int getInt() const {return a;}
};

TEST(UtilTest, Collate) {
  std::vector<test_obj> vec1 {
    test_obj(1),
    test_obj(54),
    test_obj(72364),
    test_obj(985123)
  };
  auto collated1 = collate(vec1, [](test_obj x) {
    return std::to_string(x.getInt());
  });
  EXPECT_EQ(collated1, "1, 54, 72364, 985123");

  std::vector<std::string> vec2 {
    "asd",
    "lkjg",
    "234.234.24sdfplk"
  };
  std::string target2 = "asd, lkjg, 234.234.24sdfplk";
  auto collated2 = collate<decltype(vec2)>(vec2, [](std::string x) {
    return x;
  });
  EXPECT_EQ(collated2, target2);

  auto collated3 = collate<decltype(vec1)>(vec1,
  [](test_obj x) {
    return std::to_string(x.getInt());
  },
  [](std::string a, std::string b) {
    return a + " AYY LMAO " + b;
  });
  EXPECT_EQ(collated3, "1 AYY LMAO 54 AYY LMAO 72364 AYY LMAO 985123");

  auto collated4 = collate(vec2);
  EXPECT_EQ(collated4, target2);
}

TEST(UtilTest, Split) {
  auto splitted = split("Lorem ipsum dolor sit amet", ' ');
  ASSERT_EQ(splitted, std::vector<std::string>({"Lorem", "ipsum", "dolor", "sit", "amet"}));
  auto empty = split("", ' ');
  ASSERT_EQ(empty, std::vector<std::string> {});
}

TEST(UtilTest, ObjBind) {
  test_obj* obj = new test_obj(67);
  auto bound = objBind(&test_obj::getInt, obj);
  EXPECT_EQ(bound(), 67);
}
<commit_msg>Use PascalCase for test class name<commit_after>#include <vector>
#include <string>
#include <gtest/gtest.h>

#include "utils/util.hpp"

class TestObj {
private:
  int a;
public:
  TestObj(int a): a(a) {}
  int getInt() {return a;}
  int getInt() const {return a;}
};

TEST(UtilTest, Collate) {
  std::vector<TestObj> vec1 {
    TestObj(1),
    TestObj(54),
    TestObj(72364),
    TestObj(985123)
  };
  auto collated1 = collate(vec1, [](TestObj x) {
    return std::to_string(x.getInt());
  });
  EXPECT_EQ(collated1, "1, 54, 72364, 985123");

  std::vector<std::string> vec2 {
    "asd",
    "lkjg",
    "234.234.24sdfplk"
  };
  std::string target2 = "asd, lkjg, 234.234.24sdfplk";
  auto collated2 = collate<decltype(vec2)>(vec2, [](std::string x) {
    return x;
  });
  EXPECT_EQ(collated2, target2);

  auto collated3 = collate<decltype(vec1)>(vec1,
  [](TestObj x) {
    return std::to_string(x.getInt());
  },
  [](std::string a, std::string b) {
    return a + " AYY LMAO " + b;
  });
  EXPECT_EQ(collated3, "1 AYY LMAO 54 AYY LMAO 72364 AYY LMAO 985123");

  auto collated4 = collate(vec2);
  EXPECT_EQ(collated4, target2);
}

TEST(UtilTest, Split) {
  auto splitted = split("Lorem ipsum dolor sit amet", ' ');
  ASSERT_EQ(splitted, std::vector<std::string>({"Lorem", "ipsum", "dolor", "sit", "amet"}));
  auto empty = split("", ' ');
  ASSERT_EQ(empty, std::vector<std::string> {});
}

TEST(UtilTest, ObjBind) {
  TestObj* obj = new TestObj(67);
  auto bound = objBind(&TestObj::getInt, obj);
  EXPECT_EQ(bound(), 67);
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------//
//                                                                            //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation  //
// and distributed under the MIT License (MIT).                               //
//                                                                            //
// Copyright (c) 2015 Guillaume Blanc                                         //
//                                                                            //
// Permission is hereby granted, free of charge, to any person obtaining a    //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation  //
// the rights to use, copy, modify, merge, publish, distribute, sublicense,   //
// and/or sell copies of the Software, and to permit persons to whom the      //
// Software is furnished to do so, subject to the following conditions:       //
//                                                                            //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software.                        //
//                                                                            //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        //
// DEALINGS IN THE SOFTWARE.                                                  //
//                                                                            //
//----------------------------------------------------------------------------//

#include "framework/utils.h"

#include <limits>
#include <cassert>

#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/memory/allocator.h"

#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/animation/runtime/local_to_model_job.h"

#include "ozz/geometry/runtime/skinning_job.h"

#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h"

#include "framework/imgui.h"
#include "framework/mesh.h"

namespace ozz {
namespace sample {

PlaybackController::PlaybackController()
  : time_(0.f),
    playback_speed_(1.f),
    play_(true) {
}

void PlaybackController::Update(const animation::Animation& _animation,
                                float _dt) {
  if (!play_) {
    return;
  }
  const float new_time = time_ + _dt * playback_speed_;
  const float loops = new_time / _animation.duration();
  time_ = new_time - floorf(loops) * _animation.duration();
}

void PlaybackController::Reset() {
  time_ = 0.f;
  playback_speed_ = 1.f;
  play_ = true;
}

void PlaybackController::OnGui(const animation::Animation& _animation,
                               ImGui* _im_gui,
                               bool _enabled) {
  if (_im_gui->DoButton(play_ ? "Pause" : "Play", _enabled)) {
    play_ = !play_;
  }
  char szLabel[64];
  std::sprintf(szLabel, "Animation time: %.2f", time_);
  if (_im_gui->DoSlider(
    szLabel, 0.f, _animation.duration(), &time_, 1.f, _enabled)) {
    // Pause the time if slider as moved.
    play_ = false;
  }
  std::sprintf(szLabel, "Playback speed: %.2f", playback_speed_);
  _im_gui->DoSlider(szLabel, -5.f, 5.f, &playback_speed_, 1.f, _enabled);

  // Allow to reset speed if it is not the default value.
  if (_im_gui->DoButton(
    "Reset playback speed", playback_speed_ != 1.f && _enabled)) {
    playback_speed_ = 1.f;
  }
}

// Uses LocalToModelJob to compute skeleton model space posture, then forwards
// to ComputePostureBounds
void ComputeSkeletonBounds(const animation::Skeleton& _skeleton,
                           math::Box* _bound) {
  using ozz::math::Float4x4;

  assert(_bound);

  // Set a default box.
  *_bound = ozz::math::Box();

  const int num_joints = _skeleton.num_joints();
  if (!num_joints) {
    return;
  }

  // Allocate matrix array, out of memory is handled by the LocalToModelJob.
  memory::Allocator* allocator = memory::default_allocator();
  ozz::Range<ozz::math::Float4x4> models =
    allocator->AllocateRange<ozz::math::Float4x4>(num_joints);
  if (!models.begin) {
    return;
  }

  // Compute model space bind pose.
  ozz::animation::LocalToModelJob job;
  job.input = _skeleton.bind_pose();
  job.output = models;
  job.skeleton = &_skeleton;
  if (job.Run()) {
    // Forwards to posture function.
    ComputePostureBounds(models, _bound);
  }

  allocator->Deallocate(models);
}

// Loop through matrices and collect min and max bounds.
void ComputePostureBounds(ozz::Range<const ozz::math::Float4x4> _matrices,
                          math::Box* _bound) {
  assert(_bound);

  // Set a default box.
  *_bound = ozz::math::Box();

  if (!_matrices.begin || !_matrices.end) {
    return;
  }
  if (_matrices.begin > _matrices.end) {
    return;
  }

  math::SimdFloat4 min =
    math::simd_float4::Load1(std::numeric_limits<float>::max());
  math::SimdFloat4 max = -min;
  const ozz::math::Float4x4* current = _matrices.begin;
  while (current < _matrices.end) {
    min = math::Min(min, current->cols[3]);
    max = math::Max(max, current->cols[3]);
    ++current;
  }

  math::Store3PtrU(min, &_bound->min.x);
  math::Store3PtrU(max, &_bound->max.x);

  return;
}

bool LoadSkeleton(const char* _filename,
                  ozz::animation::Skeleton* _skeleton) {
  assert(_filename && _skeleton);
  ozz::log::Out() << "Loading skeleton archive " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open skeleton file " << _filename << "."
      << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::animation::Skeleton>()) {
    ozz::log::Err() << "Failed to load skeleton instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_skeleton;

  return true;
}

bool LoadAnimation(const char* _filename,
                   ozz::animation::Animation* _animation) {
  assert(_filename && _animation);
  ozz::log::Out() << "Loading animation archive: " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open animation file " << _filename <<
      "." << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::animation::Animation>()) {
    ozz::log::Err() << "Failed to load animation instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_animation;

  return true;
}

bool LoadMesh(const char* _filename,
              ozz::sample::Mesh* _mesh) {
  assert(_filename && _mesh);
  ozz::log::Out() << "Loading mesh archive: " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open mesh file " << _filename <<
      "." << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::sample::Mesh>()) {
    ozz::log::Err() << "Failed to load mesh instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_mesh;

  return true;
}
}  // sample
}  // ozz
<commit_msg>Small optimization on samples bound box computation.<commit_after>//----------------------------------------------------------------------------//
//                                                                            //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation  //
// and distributed under the MIT License (MIT).                               //
//                                                                            //
// Copyright (c) 2015 Guillaume Blanc                                         //
//                                                                            //
// Permission is hereby granted, free of charge, to any person obtaining a    //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation  //
// the rights to use, copy, modify, merge, publish, distribute, sublicense,   //
// and/or sell copies of the Software, and to permit persons to whom the      //
// Software is furnished to do so, subject to the following conditions:       //
//                                                                            //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software.                        //
//                                                                            //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        //
// DEALINGS IN THE SOFTWARE.                                                  //
//                                                                            //
//----------------------------------------------------------------------------//

#include "framework/utils.h"

#include <limits>
#include <cassert>

#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/memory/allocator.h"

#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/animation/runtime/local_to_model_job.h"

#include "ozz/geometry/runtime/skinning_job.h"

#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h"

#include "framework/imgui.h"
#include "framework/mesh.h"

namespace ozz {
namespace sample {

PlaybackController::PlaybackController()
  : time_(0.f),
    playback_speed_(1.f),
    play_(true) {
}

void PlaybackController::Update(const animation::Animation& _animation,
                                float _dt) {
  if (!play_) {
    return;
  }
  const float new_time = time_ + _dt * playback_speed_;
  const float loops = new_time / _animation.duration();
  time_ = new_time - floorf(loops) * _animation.duration();
}

void PlaybackController::Reset() {
  time_ = 0.f;
  playback_speed_ = 1.f;
  play_ = true;
}

void PlaybackController::OnGui(const animation::Animation& _animation,
                               ImGui* _im_gui,
                               bool _enabled) {
  if (_im_gui->DoButton(play_ ? "Pause" : "Play", _enabled)) {
    play_ = !play_;
  }
  char szLabel[64];
  std::sprintf(szLabel, "Animation time: %.2f", time_);
  if (_im_gui->DoSlider(
    szLabel, 0.f, _animation.duration(), &time_, 1.f, _enabled)) {
    // Pause the time if slider as moved.
    play_ = false;
  }
  std::sprintf(szLabel, "Playback speed: %.2f", playback_speed_);
  _im_gui->DoSlider(szLabel, -5.f, 5.f, &playback_speed_, 1.f, _enabled);

  // Allow to reset speed if it is not the default value.
  if (_im_gui->DoButton(
    "Reset playback speed", playback_speed_ != 1.f && _enabled)) {
    playback_speed_ = 1.f;
  }
}

// Uses LocalToModelJob to compute skeleton model space posture, then forwards
// to ComputePostureBounds
void ComputeSkeletonBounds(const animation::Skeleton& _skeleton,
                           math::Box* _bound) {
  using ozz::math::Float4x4;

  assert(_bound);

  // Set a default box.
  *_bound = ozz::math::Box();

  const int num_joints = _skeleton.num_joints();
  if (!num_joints) {
    return;
  }

  // Allocate matrix array, out of memory is handled by the LocalToModelJob.
  memory::Allocator* allocator = memory::default_allocator();
  ozz::Range<ozz::math::Float4x4> models =
    allocator->AllocateRange<ozz::math::Float4x4>(num_joints);
  if (!models.begin) {
    return;
  }

  // Compute model space bind pose.
  ozz::animation::LocalToModelJob job;
  job.input = _skeleton.bind_pose();
  job.output = models;
  job.skeleton = &_skeleton;
  if (job.Run()) {
    // Forwards to posture function.
    ComputePostureBounds(models, _bound);
  }

  allocator->Deallocate(models);
}

// Loop through matrices and collect min and max bounds.
void ComputePostureBounds(ozz::Range<const ozz::math::Float4x4> _matrices,
                          math::Box* _bound) {
  assert(_bound);

  // Set a default box.
  *_bound = ozz::math::Box();

  if (!_matrices.begin || !_matrices.end) {
    return;
  }
  if (_matrices.begin > _matrices.end) {
    return;
  }

  // Loops through matrices and stores min/max.
  // Matrices array cannot be empty, it was checked at the beginning of the function.
  const ozz::math::Float4x4* current = _matrices.begin;
  math::SimdFloat4 min = current->cols[3];
  math::SimdFloat4 max = current->cols[3];
  ++current;
  while (current < _matrices.end) {
    min = math::Min(min, current->cols[3]);
    max = math::Max(max, current->cols[3]);
    ++current;
  }

  // Stores in math::Box structure.
  math::Store3PtrU(min, &_bound->min.x);
  math::Store3PtrU(max, &_bound->max.x);

  return;
}

bool LoadSkeleton(const char* _filename,
                  ozz::animation::Skeleton* _skeleton) {
  assert(_filename && _skeleton);
  ozz::log::Out() << "Loading skeleton archive " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open skeleton file " << _filename << "."
      << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::animation::Skeleton>()) {
    ozz::log::Err() << "Failed to load skeleton instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_skeleton;

  return true;
}

bool LoadAnimation(const char* _filename,
                   ozz::animation::Animation* _animation) {
  assert(_filename && _animation);
  ozz::log::Out() << "Loading animation archive: " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open animation file " << _filename <<
      "." << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::animation::Animation>()) {
    ozz::log::Err() << "Failed to load animation instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_animation;

  return true;
}

bool LoadMesh(const char* _filename,
              ozz::sample::Mesh* _mesh) {
  assert(_filename && _mesh);
  ozz::log::Out() << "Loading mesh archive: " << _filename <<
    "." << std::endl;
  ozz::io::File file(_filename, "rb");
  if (!file.opened()) {
    ozz::log::Err() << "Failed to open mesh file " << _filename <<
      "." << std::endl;
    return false;
  }
  ozz::io::IArchive archive(&file);
  if (!archive.TestTag<ozz::sample::Mesh>()) {
    ozz::log::Err() << "Failed to load mesh instance from file " <<
      _filename << "." << std::endl;
    return false;
  }

  // Once the tag is validated, reading cannot fail.
  archive >> *_mesh;

  return true;
}
}  // sample
}  // ozz
<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/tuple.hpp>
#include <agency/detail/arithmetic_tuple_facade.hpp>
#include <agency/detail/type_traits.hpp>
#include <agency/detail/make_tuple_if_not_nested.hpp>

namespace agency
{
namespace detail
{

// shape_tuple can't just be an alias for a particular kind of tuple
// because it also requires arithmetic operators
template<class... Shapes>
class shape_tuple :
  public agency::detail::tuple<Shapes...>,
  public arithmetic_tuple_facade<shape_tuple<Shapes...>>
{
  public:
    using agency::detail::tuple<Shapes...>::tuple;
};

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
struct nested_shape
{
  using type = decltype(
    detail::tuple_cat(
      detail::make_tuple_if_not_nested<ExecutionCategory1>(std::declval<Shape1>()),
      detail::make_tuple_if_not_nested<ExecutionCategory2>(std::declval<Shape2>())
    )
  );
};

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
using nested_shape_t = typename nested_shape<
  ExecutionCategory1,
  ExecutionCategory2,
  Shape1,
  Shape2
>::type;

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
nested_shape_t<ExecutionCategory1,ExecutionCategory2,Shape1,Shape2> make_nested_shape(const Shape1& outer_shape, const Shape2& inner_shape)
{
  return detail::tuple_cat(
    detail::make_tuple_if_not_nested<ExecutionCategory1>(outer_shape),
    detail::make_tuple_if_not_nested<ExecutionCategory2>(inner_shape)
  );
}

} // end detail
} // end agency

namespace __tu
{

// tuple_traits specializations

template<class... Shapes>
struct tuple_traits<agency::detail::shape_tuple<Shapes...>>
  : __tu::tuple_traits<agency::detail::tuple<Shapes...>>
{
  using tuple_type = agency::detail::tuple<Shapes...>;
}; // end tuple_traits

} // end __tu

namespace std
{

template<class... Shapes>
struct tuple_size<agency::detail::shape_tuple<Shapes...>> : std::tuple_size<agency::detail::tuple<Shapes...>> {};

template<size_t i, class... Shapes>
struct tuple_element<i,agency::detail::shape_tuple<Shapes...>> : std::tuple_element<i,agency::detail::tuple<Shapes...>> {};

} // end namespace std

<commit_msg>Annotate make_nested_shape()<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/tuple.hpp>
#include <agency/detail/arithmetic_tuple_facade.hpp>
#include <agency/detail/type_traits.hpp>
#include <agency/detail/make_tuple_if_not_nested.hpp>

namespace agency
{
namespace detail
{

// shape_tuple can't just be an alias for a particular kind of tuple
// because it also requires arithmetic operators
template<class... Shapes>
class shape_tuple :
  public agency::detail::tuple<Shapes...>,
  public arithmetic_tuple_facade<shape_tuple<Shapes...>>
{
  public:
    using agency::detail::tuple<Shapes...>::tuple;
};

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
struct nested_shape
{
  using type = decltype(
    detail::tuple_cat(
      detail::make_tuple_if_not_nested<ExecutionCategory1>(std::declval<Shape1>()),
      detail::make_tuple_if_not_nested<ExecutionCategory2>(std::declval<Shape2>())
    )
  );
};

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
using nested_shape_t = typename nested_shape<
  ExecutionCategory1,
  ExecutionCategory2,
  Shape1,
  Shape2
>::type;

template<class ExecutionCategory1,
         class ExecutionCategory2,
         class Shape1,
         class Shape2>
__AGENCY_ANNOTATION
nested_shape_t<ExecutionCategory1,ExecutionCategory2,Shape1,Shape2> make_nested_shape(const Shape1& outer_shape, const Shape2& inner_shape)
{
  return detail::tuple_cat(
    detail::make_tuple_if_not_nested<ExecutionCategory1>(outer_shape),
    detail::make_tuple_if_not_nested<ExecutionCategory2>(inner_shape)
  );
}

} // end detail
} // end agency

namespace __tu
{

// tuple_traits specializations

template<class... Shapes>
struct tuple_traits<agency::detail::shape_tuple<Shapes...>>
  : __tu::tuple_traits<agency::detail::tuple<Shapes...>>
{
  using tuple_type = agency::detail::tuple<Shapes...>;
}; // end tuple_traits

} // end __tu

namespace std
{

template<class... Shapes>
struct tuple_size<agency::detail::shape_tuple<Shapes...>> : std::tuple_size<agency::detail::tuple<Shapes...>> {};

template<size_t i, class... Shapes>
struct tuple_element<i,agency::detail::shape_tuple<Shapes...>> : std::tuple_element<i,agency::detail::tuple<Shapes...>> {};

} // end namespace std

<|endoftext|>


<commit_before>#pragma once

#ifndef RAZ_COMPONENT_HPP
#define RAZ_COMPONENT_HPP

#include <memory>

namespace Raz {

class Component;
using ComponentPtr = std::unique_ptr<Component>;

/// Component class representing a base Component to be inherited.
class Component {
public:
  /// Gets the ID of the given component.
  /// It uses CRTP to assign a different ID to each component it is called with.
  /// This function will be compiled every time it is called with a different component type, incrementing the assigned index.
  /// Note that it must be called directly from Component, and a derived class must be given (Component::getId<DerivedComponent>()).
  /// \tparam T Type of the component to get the ID for.
  /// \return Given component's ID.
  template <typename T> static std::size_t getId();

  virtual ~Component() = default;

protected:
  Component() = default;

private:
  static std::size_t m_maxId;
};

} // namespace Raz

#include "RaZ/Component.inl"

#endif // RAZ_COMPONENT_HPP
<commit_msg>[Utils/Overlay] Added default copy/move ctor for Component<commit_after>#pragma once

#ifndef RAZ_COMPONENT_HPP
#define RAZ_COMPONENT_HPP

#include <memory>

namespace Raz {

class Component;
using ComponentPtr = std::unique_ptr<Component>;

/// Component class representing a base Component to be inherited.
class Component {
public:
  /// Gets the ID of the given component.
  /// It uses CRTP to assign a different ID to each component it is called with.
  /// This function will be compiled every time it is called with a different component type, incrementing the assigned index.
  /// Note that it must be called directly from Component, and a derived class must be given (Component::getId<DerivedComponent>()).
  /// \tparam T Type of the component to get the ID for.
  /// \return Given component's ID.
  template <typename T> static std::size_t getId();

  virtual ~Component() = default;

protected:
  Component() = default;
  Component(const Component&) = default;
  Component(Component&&) noexcept = default;

private:
  static std::size_t m_maxId;
};

} // namespace Raz

#include "RaZ/Component.inl"

#endif // RAZ_COMPONENT_HPP
<|endoftext|>


<commit_before>/* ux++ - ux implementation for C++ */

/* LICENSE - The MIT License (MIT)

Copyright (c) 2013 Tomona Nanase

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef VOLUMEOPERATE_HPP
#define	VOLUMEOPERATE_HPP

#include <unordered_map>
#include <string>
#include "EnumBase.hpp"

using namespace std;

namespace uxpp {

  /**
   * ボリュームに作用するオプションを表した列挙体です。
   */
  class VolumeOperate : public EnumBase {
  public:
    // <editor-fold desc="-- Enums --">

    enum values {
      /**
       * 変化を伴わない音量。ボリューム。
       */
      volume,

      /**
       * 変化を伴う音量。抑揚。
       */
      expression,

      /**
       * 発音の強さ。ベロシティ。
       */
      velocity,

      /**
       * 発音の増幅度。ゲイン。
       */
      gain,
    };

    // </editor-fold>

    // <editor-fold desc="-- Methods --">

    _key_exists_impl(VolumeOperate);
    _value_exists_impl(VolumeOperate);
    _toString_impl(VolumeOperate);
    _tryParse_impl(VolumeOperate);
    // </editor-fold>

  private:
    static const unordered_map<string, values> map;
  };

  const unordered_map<string, VolumeOperate::values>
          VolumeOperate::map = {
    {"volume", volume},
    {"expression", expression},
    {"velocity", velocity},
    {"gain", gain},
  };
}

#endif	/* VOLUMEOPERATE_HPP */

<commit_msg>VolumeOperateクラスのusingディレクティブを削除<commit_after>/* ux++ - ux implementation for C++ */

/* LICENSE - The MIT License (MIT)

Copyright (c) 2013 Tomona Nanase

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef VOLUMEOPERATE_HPP
#define	VOLUMEOPERATE_HPP

#include <unordered_map>
#include <string>
#include "EnumBase.hpp"

namespace uxpp {

  /**
   * ボリュームに作用するオプションを表した列挙体です。
   */
  class VolumeOperate : public EnumBase {
  public:
    // <editor-fold desc="-- Enums --">

    enum values {
      /**
       * 変化を伴わない音量。ボリューム。
       */
      volume,

      /**
       * 変化を伴う音量。抑揚。
       */
      expression,

      /**
       * 発音の強さ。ベロシティ。
       */
      velocity,

      /**
       * 発音の増幅度。ゲイン。
       */
      gain,
    };

    // </editor-fold>

    // <editor-fold desc="-- Methods --">

    _key_exists_impl(VolumeOperate);
    _value_exists_impl(VolumeOperate);
    _toString_impl(VolumeOperate);
    _tryParse_impl(VolumeOperate);
    // </editor-fold>

  private:
    static const std::unordered_map<std::string, values> map;
  };

  const std::unordered_map<std::string, VolumeOperate::values>
          VolumeOperate::map = {
    {"volume", volume},
    {"expression", expression},
    {"velocity", velocity},
    {"gain", gain},
  };
}

#endif	/* VOLUMEOPERATE_HPP */

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/desktop_capture/window_capturer.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/system_wrappers/interface/logging.h"

namespace webrtc {

class WindowCapturerTest : public testing::Test,
                           public DesktopCapturer::Callback {
 public:
  void SetUp() override {
    capturer_.reset(
        WindowCapturer::Create(DesktopCaptureOptions::CreateDefault()));
  }

  void TearDown() override {}

  // DesktopCapturer::Callback interface
  SharedMemory* CreateSharedMemory(size_t size) override { return NULL; }

  void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }

 protected:
  rtc::scoped_ptr<WindowCapturer> capturer_;
  rtc::scoped_ptr<DesktopFrame> frame_;
};

// Verify that we can enumerate windows.
TEST_F(WindowCapturerTest, Enumerate) {
  WindowCapturer::WindowList windows;
  EXPECT_TRUE(capturer_->GetWindowList(&windows));

  // Verify that window titles are set.
  for (WindowCapturer::WindowList::iterator it = windows.begin();
       it != windows.end(); ++it) {
    EXPECT_FALSE(it->title.empty());
  }
}

// Verify we can capture a window.
//
// TODO(sergeyu): Currently this test just looks at the windows that already
// exist. Ideally it should create a test window and capture from it, but there
// is no easy cross-platform way to create new windows (potentially we could
// have a python script showing Tk dialog, but launching code will differ
// between platforms).
TEST_F(WindowCapturerTest, Capture) {
  WindowCapturer::WindowList windows;
  capturer_->Start(this);
  EXPECT_TRUE(capturer_->GetWindowList(&windows));

  // Verify that we can select and capture each window.
  for (WindowCapturer::WindowList::iterator it = windows.begin();
       it != windows.end(); ++it) {
    frame_.reset();
    if (capturer_->SelectWindow(it->id)) {
      capturer_->Capture(DesktopRegion());
    }

    // If we failed to capture a window make sure it no longer exists.
    if (!frame_.get()) {
      WindowCapturer::WindowList new_list;
      EXPECT_TRUE(capturer_->GetWindowList(&new_list));
      for (WindowCapturer::WindowList::iterator new_list_it = windows.begin();
           new_list_it != windows.end(); ++new_list_it) {
        EXPECT_FALSE(it->id == new_list_it->id);
      }
      continue;
    }

    EXPECT_GT(frame_->size().width(), 0);
    EXPECT_GT(frame_->size().height(), 0);
  }
}

}  // namespace webrtc
<commit_msg>Fix an apparent typo in a unittest that caused it to not actually check the new window list it fetched.<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/desktop_capture/window_capturer.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/system_wrappers/interface/logging.h"

namespace webrtc {

class WindowCapturerTest : public testing::Test,
                           public DesktopCapturer::Callback {
 public:
  void SetUp() override {
    capturer_.reset(
        WindowCapturer::Create(DesktopCaptureOptions::CreateDefault()));
  }

  void TearDown() override {}

  // DesktopCapturer::Callback interface
  SharedMemory* CreateSharedMemory(size_t size) override { return NULL; }

  void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }

 protected:
  rtc::scoped_ptr<WindowCapturer> capturer_;
  rtc::scoped_ptr<DesktopFrame> frame_;
};

// Verify that we can enumerate windows.
TEST_F(WindowCapturerTest, Enumerate) {
  WindowCapturer::WindowList windows;
  EXPECT_TRUE(capturer_->GetWindowList(&windows));

  // Verify that window titles are set.
  for (WindowCapturer::WindowList::iterator it = windows.begin();
       it != windows.end(); ++it) {
    EXPECT_FALSE(it->title.empty());
  }
}

// Verify we can capture a window.
//
// TODO(sergeyu): Currently this test just looks at the windows that already
// exist. Ideally it should create a test window and capture from it, but there
// is no easy cross-platform way to create new windows (potentially we could
// have a python script showing Tk dialog, but launching code will differ
// between platforms).
TEST_F(WindowCapturerTest, Capture) {
  WindowCapturer::WindowList windows;
  capturer_->Start(this);
  EXPECT_TRUE(capturer_->GetWindowList(&windows));

  // Verify that we can select and capture each window.
  for (WindowCapturer::WindowList::iterator it = windows.begin();
       it != windows.end(); ++it) {
    frame_.reset();
    if (capturer_->SelectWindow(it->id)) {
      capturer_->Capture(DesktopRegion());
    }

    // If we failed to capture a window make sure it no longer exists.
    if (!frame_.get()) {
      WindowCapturer::WindowList new_list;
      EXPECT_TRUE(capturer_->GetWindowList(&new_list));
      for (WindowCapturer::WindowList::iterator new_list_it = new_list.begin();
           new_list_it != new_list.end(); ++new_list_it) {
        EXPECT_FALSE(it->id == new_list_it->id);
      }
      continue;
    }

    EXPECT_GT(frame_->size().width(), 0);
    EXPECT_GT(frame_->size().height(), 0);
  }
}

}  // namespace webrtc
<|endoftext|>