<commit_before>/* TimeManagerTest.cpp
 *
 * Kubo Ryosuke
 */

#include "test/Test.hpp"
#include "search/time/TimeManager.hpp"
#include "search/Searcher.hpp"

using namespace sunfish;

TEST(TimeManagerTest, testTimeManager) {
  Move move1(Square::s27(), Square::s26(), false);
  Move move2(Square::s83(), Square::s84(), false);
  Move moves1[] = { move1, move2, move1, move2, move1, move2, move1, move2, move1, move2, };
  Move moves2[] = { move2, move1, move2, move1, move2, move1, move2, move1, move2, move1, };
  PV pv1(10, moves1);
  PV pv2(10, moves2);

  auto inf = SearchConfig::InfinityTime;
  struct Scenario {
    bool clear;
    SearchConfig::TimeType optimumTimeMs;
    SearchConfig::TimeType maximumTimeMs;
    uint32_t elapsedMs;
    int depth;
    Score score;
    PV pv;
    bool shouldInterrupt;
  };
  Scenario scenario[] = {
    // clear optimumTimeMs maximumTimeMs elapsedMs depth score   pv shouldInterrupt
    {   true,          inf,          inf,    10000,   10,  100, pv1,          false },
    {  false,          inf,          inf,   581000,   11,  100, pv1,          false },
    {  false,          inf,          inf,   582000,   12,  100, pv2,          false }, // 97% of maximumTimeMs
    {   true,          inf,       600000,    10000,   10,  100, pv1,          false },
    {  false,          inf,       600000,   581000,   11,  100, pv1,          false },
    {  false,          inf,       600000,   582000,   12,  100, pv2,           true }, // 97% of maximumTimeMs
    {   true,       100000,       600000,    10000,   10,  100, pv1,          false },
    {  false,       100000,       600000,   581000,   11,  100, pv2,          false },
    {  false,       100000,       600000,   582000,   12,  100, pv2,           true }, // 97% of maximumTimeMs
  };

  TimeManager timeManager;

  timeManager.clearGame();

  for (size_t i = 0; i < sizeof(scenario)/sizeof(scenario[0]); i++) {
    auto s = scenario[i];
    if (s.clear) {
      timeManager.clearPosition(s.optimumTimeMs, s.maximumTimeMs);
    }
    timeManager.update(s.elapsedMs,
                       s.depth * Searcher::Depth1Ply,
                       s.score,
                       s.pv);
    ASSERT_EQ(s.shouldInterrupt, timeManager.shouldInterrupt());
  }
}
<commit_msg>Fix test<commit_after>/* TimeManagerTest.cpp
 *
 * Kubo Ryosuke
 */

#include "test/Test.hpp"
#include "search/time/TimeManager.hpp"
#include "search/Searcher.hpp"

using namespace sunfish;

TEST(TimeManagerTest, testTimeManager) {
  Move move1(Square::s27(), Square::s26(), false);
  Move move2(Square::s83(), Square::s84(), false);
  Move move3(Square::s17(), Square::s16(), true);
  Move moves1[] = { move1, move2, move3, move1, move2, move3, move1, move2, move3, move1, };
  Move moves2[] = { move2, move3, move1, move2, move3, move1, move2, move3, move1, move2, };
  Move moves3[] = { move3, move1, move2, move3, move1, move2, move3, move1, move2, move3, };
  PV pv1(10, moves1);
  PV pv2(10, moves2);
  PV pv3(10, moves3);

  auto inf = SearchConfig::InfinityTime;
  struct Scenario {
    bool clear;
    SearchConfig::TimeType optimumTimeMs;
    SearchConfig::TimeType maximumTimeMs;
    uint32_t elapsedMs;
    int depth;
    Score score;
    PV pv;
    bool shouldInterrupt;
  };
  Scenario scenario[] = {
    // clear optimumTimeMs maximumTimeMs elapsedMs depth score   pv shouldInterrupt
    {   true,          inf,          inf,    10000,   10,  100, pv1,          false },
    {  false,          inf,          inf,   581000,   11,  100, pv2,          false },
    {  false,          inf,          inf,   582000,   12,  100, pv3,          false },
    {   true,          inf,       600000,    10000,   10,  100, pv1,          false },
    {  false,          inf,       600000,   479000,   11,  100, pv2,          false },
    {  false,          inf,       600000,   480000,   12,  100, pv3,           true }, // 80% of maximumTimeMs
    {   true,       100000,       600000,    10000,   10,  100, pv1,          false },
    {  false,       100000,       600000,   479000,   11,  100, pv2,          false },
    {  false,       100000,       600000,   480000,   12,  100, pv3,           true }, // 80% of maximumTimeMs
  };

  TimeManager timeManager;

  timeManager.clearGame();

  for (size_t i = 0; i < sizeof(scenario)/sizeof(scenario[0]); i++) {
    auto s = scenario[i];
    if (s.clear) {
      timeManager.clearPosition(s.optimumTimeMs, s.maximumTimeMs);
    }
    timeManager.update(s.elapsedMs,
                       s.depth * Searcher::Depth1Ply,
                       s.score,
                       s.pv);
    ASSERT_EQ(s.shouldInterrupt, timeManager.shouldInterrupt());
  }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 Samplecount S.L.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef METHCLA_LV2_ATOM_HPP_INCLUDED
#define METHCLA_LV2_ATOM_HPP_INCLUDED

#include <cassert>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
#include "lv2/lv2plug.in/ns/ext/atom/util.h"

namespace Methcla { namespace LV2 {

    class Property
    {
    public:
        Property(LV2_URID key, LV2_URID context=0)
            : m_key(key)
            , m_context(context)
        { }

        LV2_URID key() const { return m_key; }
        LV2_URID context() const { return m_context; }

    private:
        LV2_URID m_key, m_context;
    };

    class Forge : public LV2_Atom_Forge
    {
    public:
        Forge(const LV2_Atom_Forge& forge)
            : LV2_Atom_Forge(forge)
        { }
        Forge(LV2_URID_Map* uridMap)
        {
            lv2_atom_forge_init(this, uridMap);
        }
        Forge(const Forge& other) = default;

        void setBuffer(uint8_t* data, uint32_t size)
        {
            lv2_atom_forge_set_buffer(this, data, size);
        }

        void atom(uint32_t size, uint32_t type)
        {
            lv2_atom_forge_atom(this, size, type);
        }

        void write(const void* data, uint32_t size)
        {
            lv2_atom_forge_write(this, const_cast<void*>(data), size);
        }

        Forge& operator<<(int32_t x)
        {
            lv2_atom_forge_int(this, x);
            return *this;
        }

        Forge& operator<<(int64_t x)
        {
            lv2_atom_forge_long(this, x);
            return *this;
        }

        Forge& operator<<(float x)
        {
            lv2_atom_forge_float(this, x);
            return *this;
        }

        Forge& operator<<(double x)
        {
            lv2_atom_forge_double(this, x);
            return *this;
        }

        Forge& operator<<(bool x)
        {
            lv2_atom_forge_bool(this, x);
            return *this;
        }

        Forge& operator<<(LV2_URID x)
        {
            lv2_atom_forge_urid(this, x);
            return *this;
        }

        Forge& operator<<(const char* x)
        {
            lv2_atom_forge_string(this, x, strlen(x));
            return *this;
        }

        Forge& operator<<(const std::string& x)
        {
            lv2_atom_forge_string(this, x.c_str(), x.size());
            return *this;
        }

        Forge& operator<<(const class Property& x)
        {
            lv2_atom_forge_property_head(this, x.key(), x.context());
            return *this;
        }
    };

    class Frame : public LV2_Atom_Forge_Frame
    {
    public:
        Frame(Forge& forge)
            : m_forge(forge)
        { }
        virtual ~Frame()
        {
            lv2_atom_forge_pop(&m_forge, this);
        }

        operator Forge& () { return m_forge; }

    protected:
        Forge& m_forge;
    };

    class TupleFrame : public Frame
    {
    public:
        TupleFrame(Forge& forge)
            : Frame(forge)
        {
            lv2_atom_forge_tuple(&m_forge, this);
        }
    };

    class ObjectFrame : public Frame
    {
    public:
        ObjectFrame(Forge& forge, LV2_URID id, LV2_URID otype)
            : Frame(forge)
        {
            lv2_atom_forge_blank(&m_forge, this, id, otype);
        }
    };

    //* Return true if atom is of the specified type.
    bool isa(const LV2_Atom* atom, LV2_URID type)
    {
        return atom->type == type;
    }

    //* Return true if object is of the specified type.
    bool isa(const LV2_Atom_Object* object, LV2_URID otype)
    {
        return object->body.otype == otype;
    }

    class Parser
    {
    public:
        Parser(LV2_URID_Map* map)
        {
            lv2_atom_forge_init(&m_forge, map);
        }
        Parser(const Parser& other) = default;

        bool isBlank(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Blank);
        }
        bool isResource(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Resource);
        }
        bool isObject(const LV2_Atom* atom) const
        {
            return isBlank(atom) || isResource(atom);
        }
        bool isTuple(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Tuple);
        }
        bool isSequence(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Sequence);
        }

        bool isBlank(const LV2_Atom_Object* object) const
        {
            return isBlank(reinterpret_cast<const LV2_Atom*>(object));
        }
        bool isResource(const LV2_Atom_Object* object) const
        {
            return isResource(reinterpret_cast<const LV2_Atom*>(object));
        }

        template <typename T> T cast(const LV2_Atom* atom, LV2_URID type, const char* typeName=nullptr) const
        {
            checkType(atom, type, typeName);
            return reinterpret_cast<T>(atom);
        }

        template <typename T> T cast(const LV2_Atom* atom) const
        {
            checkType(atom, m_forge.Chunk, LV2_ATOM__Chunk);
            return reinterpret_cast<T>(LV2_ATOM_BODY(atom));
        }

        template <typename T> T get(const LV2_Atom_Object* object, LV2_URID key) const;

        const LV2_Atom_Forge& forge()
        {
            return m_forge;
        }

    private:
        void argumentError(const char* typeName) const
        {
            std::stringstream msg;
            msg << "argument type error";
            if (typeName != nullptr)
                msg << ", expected " << typeName;
            throw std::invalid_argument(msg.str());
        }

        void checkType(const LV2_Atom* atom, LV2_URID type, const char* typeName=nullptr) const
        {
            if (!isa(atom, type)) argumentError(typeName);
        }

    private:
        LV2_Atom_Forge m_forge;
    };

    template <> int32_t Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Int, LV2_ATOM__Int);
        return reinterpret_cast<const LV2_Atom_Int*>(atom)->body;
    }

    template <> int64_t Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Long, LV2_ATOM__Long);
        return reinterpret_cast<const LV2_Atom_Long*>(atom)->body;
    }

    template <> float Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Float, LV2_ATOM__Float);
        return reinterpret_cast<const LV2_Atom_Float*>(atom)->body;
    }

    template <> double Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Double, LV2_ATOM__Double);
        return reinterpret_cast<const LV2_Atom_Double*>(atom)->body;
    }

    template <> LV2_URID Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.URID, LV2_ATOM__URID);
        return reinterpret_cast<const LV2_Atom_URID*>(atom)->body;
    }

    template <> const char* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.String, LV2_ATOM__String);
        return reinterpret_cast<const char*>(LV2_ATOM_BODY(atom));
    }

    template <> const LV2_Atom_Object* Parser::cast(const LV2_Atom* atom) const
    {
        if (!isObject(atom))
            argumentError(LV2_ATOM_PREFIX "Object");
        return reinterpret_cast<const LV2_Atom_Object*>(atom);
    }

    template <> const LV2_Atom_Tuple* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Tuple, LV2_ATOM__Tuple);
        return reinterpret_cast<const LV2_Atom_Tuple*>(atom);
    }

    template <> const LV2_Atom_Sequence* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Sequence, LV2_ATOM__Sequence);
        return reinterpret_cast<const LV2_Atom_Sequence*>(atom);
    }

    template <typename T> T Parser::get(const LV2_Atom_Object* object, LV2_URID key) const
    {
        const LV2_Atom* value = nullptr;
        lv2_atom_object_get(object, key, &value, nullptr);
        if (value == nullptr) {
            std::stringstream msg;
            msg << "missing key " << key;
            throw std::out_of_range(msg.str());
        }
        return cast<T>(value);
    }

    class Printer : public Parser
    {
    public:
        Printer(LV2_URID_Map* map, const LV2_URID_Unmap* unmap)
            : Parser(map)
            , m_unmap(*unmap)
        { }

        void print(std::ostream& out, const LV2_Atom* atom, size_t level=0)
        {
                   if (isa(atom, forge().Int)) {
                indent(out, level);
                out << cast<int32_t>(atom);
            } else if (isa(atom, forge().Long)) {
                indent(out, level);
                out << cast<int64_t>(atom);
            } else if (isa(atom, forge().Float)) {
                indent(out, level);
                out << cast<float>(atom);
            } else if (isa(atom, forge().Double)) {
                indent(out, level);
                out << cast<double>(atom);
            } else if (isa(atom, forge().String)) {
                indent(out, level);
                out << '"' << cast<const char*>(atom) << '"';
            } else if (isa(atom, forge().URID)) {
                indent(out, level);
                out << '<' << unmap(cast<LV2_URID>(atom)) << '>';
            } else if (isTuple(atom)) {
                indent(out, level);
                out << '[' << std::endl;
                const LV2_Atom_Tuple* tuple = cast<const LV2_Atom_Tuple*>(atom);
                for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple);
                     !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (atom)->size, (iter));
                     (iter) = lv2_atom_tuple_next(iter)) {
                    print(out, iter, level+4);
                    out << std::endl;
                }
                indent(out, level);
                out << ']';
            //} else if (isSequence(atom)) {
            } else if (isObject(atom)) {
                indent(out, level);
                const LV2_Atom_Object* object = cast<const LV2_Atom_Object*>(atom);
                if (isResource(object))
                    out << "<" << unmap(object->body.id) << "> ";
                //else if (isBlank(object))
                    //out << "[] ";
                out << '{' << std::endl;
                indent(out, level+4);
                out << "<rdf:type>:" << std::endl;
                indent(out, level+8);
                out << '<' << unmap(object->body.otype) << '>' << std::endl;
                LV2_ATOM_OBJECT_FOREACH(object, iter) {
                    indent(out, level+4);
                    out << '<' << unmap(iter->key) << ">:" << std::endl;
                    print(out, &iter->value, level+8);
                    out << std::endl;
                }
                indent(out, level);
                out << '}';
            } else {
                indent(out, level);
                out << "<Atom " << atom->type << ">";
            }
        }

    private:
        const char* unmap(LV2_URID urid) const
        {
            return m_unmap.unmap(m_unmap.handle, urid);
        }

        static void indent(std::ostream& stream, size_t n)
        {
            for (size_t i=0; i < n; i++) {
                stream << ' ';
            }
        }

    private:
        LV2_URID_Unmap m_unmap;
    };

    //
// class ObjectIterator
//   : public boost::iterator_facade<
//         ObjectIterator
//       , Property const
//       , boost::input_iterator_tag
//     >
// {
//  public:
//     ObjectIterator()
//       : m_node(0) {}

//     explicit ObjectIterator(node_base* p)
//       : m_node(p) {}

//  private:
//     friend class boost::iterator_core_access;

//     void increment() { m_node = m_node->next(); }

//     bool equal(const_node_iterator const& other) const
//     {
//         return this->m_node == other.m_node;
//     }

//     node_base const& dereference() const { return *m_node; }

//     node_base const* m_node;
// };

//class Property
//{
//public:
	//Property(const LV2_Atom_Property_Body* prop)
		//: m_impl(prop)
	//{ }

//private:
	//const LV2_Atom_Property* m_impl;
//};

//class Object
//{
//public:
	//Object(const LV2_Atom_Object* obj)
		//: m_impl(obj)
	//{ }

	//class const_iterator
	//{
	//public:
		//explicit const_iterator(const LV2_Atom_Object_Body* obj)
			//: m_iter(it)
		//{ }

		//operator bool () const { return !lv2_atom_}
	//};

	//const_iterator begin() const { return ObjectIterator(m_impl); }
//private:
	//const LV2_Atom_Object_Body* m_impl;
//};

}; };

#endif // METHCLA_LV2_ATOM_HPP_INCLUDED
<commit_msg>Add operator for copying an existing atom to output stream<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef METHCLA_LV2_ATOM_HPP_INCLUDED
#define METHCLA_LV2_ATOM_HPP_INCLUDED

#include <cassert>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
#include "lv2/lv2plug.in/ns/ext/atom/util.h"

namespace Methcla { namespace LV2 {

    class Property
    {
    public:
        Property(LV2_URID key, LV2_URID context=0)
            : m_key(key)
            , m_context(context)
        { }

        LV2_URID key() const { return m_key; }
        LV2_URID context() const { return m_context; }

    private:
        LV2_URID m_key, m_context;
    };

    class Forge : public LV2_Atom_Forge
    {
    public:
        Forge(const LV2_Atom_Forge& forge)
            : LV2_Atom_Forge(forge)
        { }
        Forge(LV2_URID_Map* uridMap)
        {
            lv2_atom_forge_init(this, uridMap);
        }
        Forge(const Forge& other) = default;

        void setBuffer(uint8_t* data, uint32_t size)
        {
            lv2_atom_forge_set_buffer(this, data, size);
        }

        void atom(uint32_t size, uint32_t type)
        {
            lv2_atom_forge_atom(this, size, type);
        }

        void write(const void* data, uint32_t size)
        {
            lv2_atom_forge_write(this, const_cast<void*>(data), size);
        }

        Forge& operator<<(int32_t x)
        {
            lv2_atom_forge_int(this, x);
            return *this;
        }

        Forge& operator<<(int64_t x)
        {
            lv2_atom_forge_long(this, x);
            return *this;
        }

        Forge& operator<<(float x)
        {
            lv2_atom_forge_float(this, x);
            return *this;
        }

        Forge& operator<<(double x)
        {
            lv2_atom_forge_double(this, x);
            return *this;
        }

        Forge& operator<<(bool x)
        {
            lv2_atom_forge_bool(this, x);
            return *this;
        }

        Forge& operator<<(LV2_URID x)
        {
            lv2_atom_forge_urid(this, x);
            return *this;
        }

        Forge& operator<<(const char* x)
        {
            lv2_atom_forge_string(this, x, strlen(x));
            return *this;
        }

        Forge& operator<<(const std::string& x)
        {
            lv2_atom_forge_string(this, x.c_str(), x.size());
            return *this;
        }

        Forge& operator<<(const class Property& x)
        {
            lv2_atom_forge_property_head(this, x.key(), x.context());
            return *this;
        }

        Forge& operator<<(const LV2_Atom* x)
        {
            lv2_atom_forge_raw(this, x, sizeof(LV2_Atom) + x->size);
            return *this;
        }
    };

    class Frame : public LV2_Atom_Forge_Frame
    {
    public:
        Frame(Forge& forge)
            : m_forge(forge)
        { }
        virtual ~Frame()
        {
            lv2_atom_forge_pop(&m_forge, this);
        }

        operator Forge& () { return m_forge; }

    protected:
        Forge& m_forge;
    };

    class TupleFrame : public Frame
    {
    public:
        TupleFrame(Forge& forge)
            : Frame(forge)
        {
            lv2_atom_forge_tuple(&m_forge, this);
        }
    };

    class ObjectFrame : public Frame
    {
    public:
        ObjectFrame(Forge& forge, LV2_URID id, LV2_URID otype)
            : Frame(forge)
        {
            lv2_atom_forge_blank(&m_forge, this, id, otype);
        }
    };

    //* Return true if atom is of the specified type.
    bool isa(const LV2_Atom* atom, LV2_URID type)
    {
        return atom->type == type;
    }

    //* Return true if object is of the specified type.
    bool isa(const LV2_Atom_Object* object, LV2_URID otype)
    {
        return object->body.otype == otype;
    }

    class Parser
    {
    public:
        Parser(LV2_URID_Map* map)
        {
            lv2_atom_forge_init(&m_forge, map);
        }
        Parser(const Parser& other) = default;

        bool isBlank(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Blank);
        }
        bool isResource(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Resource);
        }
        bool isObject(const LV2_Atom* atom) const
        {
            return isBlank(atom) || isResource(atom);
        }
        bool isTuple(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Tuple);
        }
        bool isSequence(const LV2_Atom* atom) const
        {
            return isa(atom, m_forge.Sequence);
        }

        bool isBlank(const LV2_Atom_Object* object) const
        {
            return isBlank(reinterpret_cast<const LV2_Atom*>(object));
        }
        bool isResource(const LV2_Atom_Object* object) const
        {
            return isResource(reinterpret_cast<const LV2_Atom*>(object));
        }

        template <typename T> T cast(const LV2_Atom* atom, LV2_URID type, const char* typeName=nullptr) const
        {
            checkType(atom, type, typeName);
            return reinterpret_cast<T>(atom);
        }

        template <typename T> T cast(const LV2_Atom* atom) const
        {
            checkType(atom, m_forge.Chunk, LV2_ATOM__Chunk);
            return reinterpret_cast<T>(LV2_ATOM_BODY(atom));
        }

        template <typename T> T get(const LV2_Atom_Object* object, LV2_URID key) const;

        const LV2_Atom_Forge& forge()
        {
            return m_forge;
        }

    private:
        void argumentError(const char* typeName) const
        {
            std::stringstream msg;
            msg << "argument type error";
            if (typeName != nullptr)
                msg << ", expected " << typeName;
            throw std::invalid_argument(msg.str());
        }

        void checkType(const LV2_Atom* atom, LV2_URID type, const char* typeName=nullptr) const
        {
            if (!isa(atom, type)) argumentError(typeName);
        }

    private:
        LV2_Atom_Forge m_forge;
    };

    template <> int32_t Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Int, LV2_ATOM__Int);
        return reinterpret_cast<const LV2_Atom_Int*>(atom)->body;
    }

    template <> int64_t Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Long, LV2_ATOM__Long);
        return reinterpret_cast<const LV2_Atom_Long*>(atom)->body;
    }

    template <> float Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Float, LV2_ATOM__Float);
        return reinterpret_cast<const LV2_Atom_Float*>(atom)->body;
    }

    template <> double Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Double, LV2_ATOM__Double);
        return reinterpret_cast<const LV2_Atom_Double*>(atom)->body;
    }

    template <> LV2_URID Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.URID, LV2_ATOM__URID);
        return reinterpret_cast<const LV2_Atom_URID*>(atom)->body;
    }

    template <> const char* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.String, LV2_ATOM__String);
        return reinterpret_cast<const char*>(LV2_ATOM_BODY(atom));
    }

    template <> const LV2_Atom_Object* Parser::cast(const LV2_Atom* atom) const
    {
        if (!isObject(atom))
            argumentError(LV2_ATOM_PREFIX "Object");
        return reinterpret_cast<const LV2_Atom_Object*>(atom);
    }

    template <> const LV2_Atom_Tuple* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Tuple, LV2_ATOM__Tuple);
        return reinterpret_cast<const LV2_Atom_Tuple*>(atom);
    }

    template <> const LV2_Atom_Sequence* Parser::cast(const LV2_Atom* atom) const
    {
        checkType(atom, m_forge.Sequence, LV2_ATOM__Sequence);
        return reinterpret_cast<const LV2_Atom_Sequence*>(atom);
    }

    template <typename T> T Parser::get(const LV2_Atom_Object* object, LV2_URID key) const
    {
        const LV2_Atom* value = nullptr;
        lv2_atom_object_get(object, key, &value, nullptr);
        if (value == nullptr) {
            std::stringstream msg;
            msg << "missing key " << key;
            throw std::out_of_range(msg.str());
        }
        return cast<T>(value);
    }

    class Printer : public Parser
    {
    public:
        Printer(LV2_URID_Map* map, const LV2_URID_Unmap* unmap)
            : Parser(map)
            , m_unmap(*unmap)
        { }

        void print(std::ostream& out, const LV2_Atom* atom, size_t level=0)
        {
                   if (isa(atom, forge().Int)) {
                indent(out, level);
                out << cast<int32_t>(atom);
            } else if (isa(atom, forge().Long)) {
                indent(out, level);
                out << cast<int64_t>(atom);
            } else if (isa(atom, forge().Float)) {
                indent(out, level);
                out << cast<float>(atom);
            } else if (isa(atom, forge().Double)) {
                indent(out, level);
                out << cast<double>(atom);
            } else if (isa(atom, forge().String)) {
                indent(out, level);
                out << '"' << cast<const char*>(atom) << '"';
            } else if (isa(atom, forge().URID)) {
                indent(out, level);
                out << '<' << unmap(cast<LV2_URID>(atom)) << '>';
            } else if (isTuple(atom)) {
                indent(out, level);
                out << '[' << std::endl;
                const LV2_Atom_Tuple* tuple = cast<const LV2_Atom_Tuple*>(atom);
                for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple);
                     !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (atom)->size, (iter));
                     (iter) = lv2_atom_tuple_next(iter)) {
                    print(out, iter, level+4);
                    out << std::endl;
                }
                indent(out, level);
                out << ']';
            //} else if (isSequence(atom)) {
            } else if (isObject(atom)) {
                indent(out, level);
                const LV2_Atom_Object* object = cast<const LV2_Atom_Object*>(atom);
                if (isResource(object))
                    out << "<" << unmap(object->body.id) << "> ";
                //else if (isBlank(object))
                    //out << "[] ";
                out << '{' << std::endl;
                indent(out, level+4);
                out << "<rdf:type>:" << std::endl;
                indent(out, level+8);
                out << '<' << unmap(object->body.otype) << '>' << std::endl;
                LV2_ATOM_OBJECT_FOREACH(object, iter) {
                    indent(out, level+4);
                    out << '<' << unmap(iter->key) << ">:" << std::endl;
                    print(out, &iter->value, level+8);
                    out << std::endl;
                }
                indent(out, level);
                out << '}';
            } else {
                indent(out, level);
                out << "<Atom " << atom->type << ">";
            }
        }

    private:
        const char* unmap(LV2_URID urid) const
        {
            return m_unmap.unmap(m_unmap.handle, urid);
        }

        static void indent(std::ostream& stream, size_t n)
        {
            for (size_t i=0; i < n; i++) {
                stream << ' ';
            }
        }

    private:
        LV2_URID_Unmap m_unmap;
    };

    //
// class ObjectIterator
//   : public boost::iterator_facade<
//         ObjectIterator
//       , Property const
//       , boost::input_iterator_tag
//     >
// {
//  public:
//     ObjectIterator()
//       : m_node(0) {}

//     explicit ObjectIterator(node_base* p)
//       : m_node(p) {}

//  private:
//     friend class boost::iterator_core_access;

//     void increment() { m_node = m_node->next(); }

//     bool equal(const_node_iterator const& other) const
//     {
//         return this->m_node == other.m_node;
//     }

//     node_base const& dereference() const { return *m_node; }

//     node_base const* m_node;
// };

//class Property
//{
//public:
	//Property(const LV2_Atom_Property_Body* prop)
		//: m_impl(prop)
	//{ }

//private:
	//const LV2_Atom_Property* m_impl;
//};

//class Object
//{
//public:
	//Object(const LV2_Atom_Object* obj)
		//: m_impl(obj)
	//{ }

	//class const_iterator
	//{
	//public:
		//explicit const_iterator(const LV2_Atom_Object_Body* obj)
			//: m_iter(it)
		//{ }

		//operator bool () const { return !lv2_atom_}
	//};

	//const_iterator begin() const { return ObjectIterator(m_impl); }
//private:
	//const LV2_Atom_Object_Body* m_impl;
//};

}; };

#endif // METHCLA_LV2_ATOM_HPP_INCLUDED
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/SafeInt.h>
#include <transport/RendezvousSession.h>

#if CONFIG_NETWORK_LAYER_BLE
#include <transport/BLE.h>
#endif // CONFIG_NETWORK_LAYER_BLE

static const size_t kMax_SecureSDU_Length          = 1024;
static constexpr uint32_t kSpake2p_Iteration_Count = 50000;
static const char * kSpake2pKeyExchangeSalt        = "SPAKE2P Key Exchange Salt";

namespace chip {

enum NetworkProvisioningMsgTypes : uint8_t
{
    kWiFiAssociationRequest = 0,
    kIPAddressAssigned      = 1,
};

CHIP_ERROR RendezvousSession::Init()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    mParams = params;
    VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mParams.HasLocalNodeId(), err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(mParams.HasSetupPINCode(), err = CHIP_ERROR_INVALID_ARGUMENT);

    err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#if CONFIG_NETWORK_LAYER_BLE
    {
        Transport::BLE * transport = new Transport::BLE();
        err                        = transport->Init(this, mParams);
        mTransport                 = transport;
        mTransport->Retain();
        transport->Release();
    }
#endif // CONFIG_NETWORK_LAYER_BLE
    SuccessOrExit(err);

    if (mParams.HasDiscriminator() == false)
    {
        err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
    }

exit:
    return err;
}

RendezvousSession::~RendezvousSession()
{
    if (mTransport)
    {
        mTransport->Release();
        mTransport = nullptr;
    }

    mDelegate = nullptr;
}

CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = mPairingInProgress ? SendPairingMessage(msgBuf)
                                        : SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
                                                            NetworkProvisioningMsgTypes::kWiFiAssociationRequest, msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
    return err;
}

CHIP_ERROR RendezvousSession::AssignedIPAddress(IPAddress & deviceAddr)
{
    CHIP_ERROR err                = CHIP_NO_ERROR;
    System::PacketBuffer * buffer = System::PacketBuffer::New();

    char * addrStr = deviceAddr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());
    VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);

    buffer->SetDataLength(strlen(addrStr) + 1);

    err = SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning, NetworkProvisioningMsgTypes::kIPAddressAssigned, buffer);
    SuccessOrExit(err);

    mDeviceAddress = deviceAddr;
    return err;

exit:
    OnRendezvousError(err);
    return err;
}

CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader header;
    uint16_t headerSize = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);
    err = mTransport->SendMessage(header, Header::Flags::None(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::SendSecureMessage(Protocols::CHIPProtocolId protocol, uint8_t msgType, System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    const uint16_t headerSize = payloadHeader.EncodeSizeBytes();
    uint16_t actualEncodedHeaderSize;
    uint8_t * data    = nullptr;
    uint16_t totalLen = 0;
    uint16_t taglen   = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(CanCastTo<uint16_t>(headerSize + msgBuf->TotalLength()), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    packetHeader
        .SetSourceNodeId(mParams.GetLocalNodeId())           //
        .SetMessageId(mSecureMessageIndex)                   //
        .SetEncryptionKeyID(mPairingSession.GetLocalKeyId()) //
        .SetPayloadLength(static_cast<uint16_t>(headerSize + msgBuf->TotalLength()));

    payloadHeader.SetProtocolID(protocol).SetMessageType(msgType);

    VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY);

    msgBuf->SetStart(msgBuf->Start() - headerSize);
    data     = msgBuf->Start();
    totalLen = msgBuf->TotalLength();

    err = payloadHeader.Encode(data, totalLen, &actualEncodedHeaderSize);
    SuccessOrExit(err);

    err = mSecureSession.Encrypt(data, totalLen, data, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = mac.Encode(packetHeader, &data[totalLen], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    VerifyOrExit(CanCastTo<uint16_t>(totalLen + taglen), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    msgBuf->SetDataLength(static_cast<uint16_t>(totalLen + taglen));

    err = mTransport->SendMessage(packetHeader, payloadHeader.GetEncodePacketFlags(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

    mSecureMessageIndex++;
    msgBuf = nullptr;

exit:
    return err;
}

void RendezvousSession::OnPairingError(CHIP_ERROR err)
{
    mPairingInProgress = false;
    mDelegate->OnRendezvousError(err);
    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingFailed);
}

void RendezvousSession::OnPairingComplete()
{
    mPairingInProgress = false;

    CHIP_ERROR err = mPairingSession.DeriveSecureSession((const unsigned char *) kSpake2pI2RSessionInfo,
                                                         strlen(kSpake2pI2RSessionInfo), mSecureSession);
    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Ble, "Failed to initialize a secure session: %s", ErrorStr(err)));

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess);
    mDelegate->OnRendezvousConnectionOpened();

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionOpened()
{
    if (mParams.HasDiscriminator())
    {
        CHIP_ERROR err = Pair(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionClosed()
{
    mDelegate->OnRendezvousConnectionClosed();

    if (!mParams.HasDiscriminator() && !mParams.HasConnectionObject())
    {
        mSecureSession.Reset();
        CHIP_ERROR err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousError(CHIP_ERROR err)
{
    mDelegate->OnRendezvousError(err);
}

void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    err = mPairingInProgress ? HandlePairingMessage(msgBuf) : HandleSecureMessage(msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
}

CHIP_ERROR RendezvousSession::HandlePairingMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    uint16_t headerSize = 0;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);

    err = mPairingSession.HandlePeerMessage(packetHeader, msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::HandleIPAddressAssignment(System::PacketBuffer * buffer)
{
    if (IPAddress::FromString(Uint8::to_const_char(buffer->Start()), buffer->DataLength(), mDeviceAddress))
    {
        return CHIP_NO_ERROR;
    }

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningFailed);
    return CHIP_ERROR_INVALID_ADDRESS;
}

CHIP_ERROR RendezvousSession::HandleSecureMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    uint16_t headerSize            = 0;
    uint8_t * data                 = nullptr;
    uint8_t * plainText            = nullptr;
    uint16_t len                   = 0;
    uint16_t decodedSize           = 0;
    uint16_t taglen                = 0;
    System::PacketBuffer * origMsg = nullptr;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);
    msgBuf->ConsumeHead(headerSize);

    headerSize = payloadHeader.EncodeSizeBytes();
    data       = msgBuf->Start();
    len        = msgBuf->TotalLength();

#if CHIP_SYSTEM_CONFIG_USE_LWIP
    /* This is a workaround for the case where PacketBuffer payload is not
       allocated as an inline buffer to PacketBuffer structure */
    origMsg = msgBuf;
    msgBuf  = PacketBuffer::NewWithAvailableSize(len);
    msgBuf->SetDataLength(len, msgBuf);
#endif
    plainText = msgBuf->Start();

    // TODO: We need length checks here!  https://github.com/project-chip/connectedhomeip/issues/2928
    err = mac.Decode(packetHeader, &data[packetHeader.GetPayloadLength()], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    len = static_cast<uint16_t>(len - taglen);
    msgBuf->SetDataLength(len);

    err = mSecureSession.Decrypt(data, len, plainText, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = payloadHeader.Decode(packetHeader.GetFlags(), plainText, headerSize, &decodedSize);
    SuccessOrExit(err);
    VerifyOrExit(headerSize == decodedSize, err = CHIP_ERROR_INCORRECT_STATE);

    msgBuf->ConsumeHead(headerSize);

    if (payloadHeader.GetProtocolID() == Protocols::kChipProtocol_NetworkProvisioning &&
        payloadHeader.GetMessageType() == NetworkProvisioningMsgTypes::kIPAddressAssigned)
    {
        err = HandleIPAddressAssignment(msgBuf);
        SuccessOrExit(err);

        mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess);
    }
    // else .. TBD once application dependency on this message has been removed, enable the else condition
    {
        mDelegate->OnRendezvousMessageReceived(msgBuf);
    }

    msgBuf = nullptr;

exit:
    if (origMsg != nullptr)
    {
        PacketBuffer::Free(origMsg);
    }

    return err;
}

CHIP_ERROR RendezvousSession::WaitForPairing(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.WaitForPairing(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                          strlen(kSpake2pKeyExchangeSalt), nodeId, 0, this);
}

CHIP_ERROR RendezvousSession::Pair(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.Pair(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                strlen(kSpake2pKeyExchangeSalt), nodeId, mNextKeyId++, this);
}

} // namespace chip
<commit_msg>Restyled by whitespace<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/SafeInt.h>
#include <transport/RendezvousSession.h>

#if CONFIG_NETWORK_LAYER_BLE
#include <transport/BLE.h>
#endif // CONFIG_NETWORK_LAYER_BLE

static const size_t kMax_SecureSDU_Length          = 1024;
static constexpr uint32_t kSpake2p_Iteration_Count = 50000;
static const char * kSpake2pKeyExchangeSalt        = "SPAKE2P Key Exchange Salt";

namespace chip {

enum NetworkProvisioningMsgTypes : uint8_t
{
    kWiFiAssociationRequest = 0,
    kIPAddressAssigned      = 1,
};

CHIP_ERROR RendezvousSession::Init()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    mParams = params;
    VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mParams.HasLocalNodeId(), err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(mParams.HasSetupPINCode(), err = CHIP_ERROR_INVALID_ARGUMENT);

    err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#if CONFIG_NETWORK_LAYER_BLE
    {
        Transport::BLE * transport = new Transport::BLE();
        err                        = transport->Init(this, mParams);
        mTransport                 = transport;
        mTransport->Retain();
        transport->Release();
    }
#endif // CONFIG_NETWORK_LAYER_BLE
    SuccessOrExit(err);

    if (mParams.HasDiscriminator() == false)
    {
        err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
    }

exit:
    return err;
}

RendezvousSession::~RendezvousSession()
{
    if (mTransport)
    {
        mTransport->Release();
        mTransport = nullptr;
    }

    mDelegate = nullptr;
}

CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = mPairingInProgress ? SendPairingMessage(msgBuf)
                                        : SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
                                                            NetworkProvisioningMsgTypes::kWiFiAssociationRequest, msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
    return err;
}

CHIP_ERROR RendezvousSession::AssignedIPAddress(IPAddress & deviceAddr)
{
    CHIP_ERROR err                = CHIP_NO_ERROR;
    System::PacketBuffer * buffer = System::PacketBuffer::New();

    char * addrStr = deviceAddr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());
    VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);

    buffer->SetDataLength(strlen(addrStr) + 1);

    err = SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning, NetworkProvisioningMsgTypes::kIPAddressAssigned, buffer);
    SuccessOrExit(err);

    mDeviceAddress = deviceAddr;
    return err;

exit:
    OnRendezvousError(err);
    return err;
}

CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader header;
    uint16_t headerSize = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);
    err = mTransport->SendMessage(header, Header::Flags::None(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::SendSecureMessage(Protocols::CHIPProtocolId protocol, uint8_t msgType, System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    const uint16_t headerSize = payloadHeader.EncodeSizeBytes();
    uint16_t actualEncodedHeaderSize;
    uint8_t * data    = nullptr;
    uint16_t totalLen = 0;
    uint16_t taglen   = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(CanCastTo<uint16_t>(headerSize + msgBuf->TotalLength()), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    packetHeader
        .SetSourceNodeId(mParams.GetLocalNodeId())           //
        .SetMessageId(mSecureMessageIndex)                   //
        .SetEncryptionKeyID(mPairingSession.GetLocalKeyId()) //
        .SetPayloadLength(static_cast<uint16_t>(headerSize + msgBuf->TotalLength()));

    payloadHeader.SetProtocolID(protocol).SetMessageType(msgType);

    VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY);

    msgBuf->SetStart(msgBuf->Start() - headerSize);
    data     = msgBuf->Start();
    totalLen = msgBuf->TotalLength();

    err = payloadHeader.Encode(data, totalLen, &actualEncodedHeaderSize);
    SuccessOrExit(err);

    err = mSecureSession.Encrypt(data, totalLen, data, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = mac.Encode(packetHeader, &data[totalLen], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    VerifyOrExit(CanCastTo<uint16_t>(totalLen + taglen), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    msgBuf->SetDataLength(static_cast<uint16_t>(totalLen + taglen));

    err = mTransport->SendMessage(packetHeader, payloadHeader.GetEncodePacketFlags(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

    mSecureMessageIndex++;
    msgBuf = nullptr;

exit:
    return err;
}

void RendezvousSession::OnPairingError(CHIP_ERROR err)
{
    mPairingInProgress = false;
    mDelegate->OnRendezvousError(err);
    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingFailed);
}

void RendezvousSession::OnPairingComplete()
{
    mPairingInProgress = false;

    CHIP_ERROR err = mPairingSession.DeriveSecureSession((const unsigned char *) kSpake2pI2RSessionInfo,
                                                         strlen(kSpake2pI2RSessionInfo), mSecureSession);
    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Ble, "Failed to initialize a secure session: %s", ErrorStr(err)));

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess);
    mDelegate->OnRendezvousConnectionOpened();

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionOpened()
{
    if (mParams.HasDiscriminator())
    {
        CHIP_ERROR err = Pair(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionClosed()
{
    mDelegate->OnRendezvousConnectionClosed();

    if (!mParams.HasDiscriminator() && !mParams.HasConnectionObject())
    {
        mSecureSession.Reset();
        CHIP_ERROR err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousError(CHIP_ERROR err)
{
    mDelegate->OnRendezvousError(err);
}

void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    err = mPairingInProgress ? HandlePairingMessage(msgBuf) : HandleSecureMessage(msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
}

CHIP_ERROR RendezvousSession::HandlePairingMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    uint16_t headerSize = 0;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);

    err = mPairingSession.HandlePeerMessage(packetHeader, msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::HandleIPAddressAssignment(System::PacketBuffer * buffer)
{
    if (IPAddress::FromString(Uint8::to_const_char(buffer->Start()), buffer->DataLength(), mDeviceAddress))
    {
        return CHIP_NO_ERROR;
    }

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningFailed);
    return CHIP_ERROR_INVALID_ADDRESS;
}

CHIP_ERROR RendezvousSession::HandleSecureMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    uint16_t headerSize            = 0;
    uint8_t * data                 = nullptr;
    uint8_t * plainText            = nullptr;
    uint16_t len                   = 0;
    uint16_t decodedSize           = 0;
    uint16_t taglen                = 0;
    System::PacketBuffer * origMsg = nullptr;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);
    msgBuf->ConsumeHead(headerSize);

    headerSize = payloadHeader.EncodeSizeBytes();
    data       = msgBuf->Start();
    len        = msgBuf->TotalLength();

#if CHIP_SYSTEM_CONFIG_USE_LWIP
    /* This is a workaround for the case where PacketBuffer payload is not
       allocated as an inline buffer to PacketBuffer structure */
    origMsg = msgBuf;
    msgBuf  = PacketBuffer::NewWithAvailableSize(len);
    msgBuf->SetDataLength(len, msgBuf);
#endif
    plainText = msgBuf->Start();

    // TODO: We need length checks here!  https://github.com/project-chip/connectedhomeip/issues/2928
    err = mac.Decode(packetHeader, &data[packetHeader.GetPayloadLength()], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    len = static_cast<uint16_t>(len - taglen);
    msgBuf->SetDataLength(len);

    err = mSecureSession.Decrypt(data, len, plainText, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = payloadHeader.Decode(packetHeader.GetFlags(), plainText, headerSize, &decodedSize);
    SuccessOrExit(err);
    VerifyOrExit(headerSize == decodedSize, err = CHIP_ERROR_INCORRECT_STATE);

    msgBuf->ConsumeHead(headerSize);

    if (payloadHeader.GetProtocolID() == Protocols::kChipProtocol_NetworkProvisioning &&
        payloadHeader.GetMessageType() == NetworkProvisioningMsgTypes::kIPAddressAssigned)
    {
        err = HandleIPAddressAssignment(msgBuf);
        SuccessOrExit(err);

        mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess);
    }
    // else .. TBD once application dependency on this message has been removed, enable the else condition
    {
        mDelegate->OnRendezvousMessageReceived(msgBuf);
    }

    msgBuf = nullptr;

exit:
    if (origMsg != nullptr)
    {
        PacketBuffer::Free(origMsg);
    }

    return err;
}

CHIP_ERROR RendezvousSession::WaitForPairing(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.WaitForPairing(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                          strlen(kSpake2pKeyExchangeSalt), nodeId, 0, this);
}

CHIP_ERROR RendezvousSession::Pair(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.Pair(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                strlen(kSpake2pKeyExchangeSalt), nodeId, mNextKeyId++, this);
}

} // namespace chip
<|endoftext|>


<commit_before>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include "libmesh/distributed_mesh.h"
#include "libmesh/replicated_mesh.h"
#include "libmesh/checkpoint_io.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/partitioner.h"

#include "test_comm.h"

// THE CPPUNIT_TEST_SUITE_END macro expands to code that involves
// std::auto_ptr, which in turn produces -Wdeprecated-declarations
// warnings.  These can be ignored in GCC as long as we wrap the
// offending code in appropriate pragmas.  We can't get away with a
// single ignore_warnings.h inclusion at the beginning of this file,
// since the libmesh headers pull in a restore_warnings.h at some
// point.  We also don't bother restoring warnings at the end of this
// file since it's not a header.
#include <libmesh/ignore_warnings.h>

using namespace libMesh;

class CheckpointIOTest : public CppUnit::TestCase {
  /**
   * This test verifies that we can write files with the CheckpointIO object.
   */
public:
  CPPUNIT_TEST_SUITE( CheckpointIOTest );

  CPPUNIT_TEST( testAsciiDistRepSplitter );
  CPPUNIT_TEST( testBinaryDistRepSplitter );
  CPPUNIT_TEST( testAsciiRepDistSplitter );
  CPPUNIT_TEST( testBinaryRepDistSplitter );
  CPPUNIT_TEST( testAsciiRepRepSplitter );
  CPPUNIT_TEST( testBinaryRepRepSplitter );
  CPPUNIT_TEST( testAsciiDistDistSplitter );
  CPPUNIT_TEST( testBinaryDistDistSplitter );

  CPPUNIT_TEST_SUITE_END();

protected:

public:
  void setUp()
  {
  }

  void tearDown()
  {
  }

  // Test that we can write multiple checkpoint files from a single processor.
  template <typename MeshA, typename MeshB>
  void testSplitter(bool binary, bool using_distmesh)
  {
    // In this test, we partition the mesh into n_procs parts.  Don't
    // try to partition a DistributedMesh into more parts than we have
    // processors, though.
    const unsigned int n_procs = using_distmesh ?
      std::min(static_cast<unsigned int>(2), TestCommWorld->size()) :
      2;

    // The number of elements in the original mesh.  For verification
    // later.
    dof_id_type original_n_elem = 0;

    const std::string filename =
      std::string("checkpoint_splitter.cp") + (binary ? "r" : "a");

    {
      MeshA mesh(*TestCommWorld);

      MeshTools::Generation::build_square(mesh,
                                          4,  4,
                                          0., 1.,
                                          0., 1.,
                                          QUAD4);

      // Store the number of elements that were in the original mesh.
      original_n_elem = mesh.n_elem();

      // Partition the mesh into n_procs pieces
      mesh.partition(n_procs);

      // Write out checkpoint files for each piece.  Since on a
      // ReplicatedMesh we might have more pieces than we do
      // processors, some processors may have to write out more than
      // one piece.
      CheckpointIO cpr(mesh);
      cpr.current_processor_ids().clear();
      for (processor_id_type pid = mesh.processor_id(); pid < n_procs; pid += mesh.n_processors())
        cpr.current_processor_ids().push_back(pid);
      cpr.current_n_processors() = n_procs;
      cpr.binary() = binary;
      cpr.parallel() = true;
      cpr.write(filename);
    }

    TestCommWorld->barrier();

    // Test that we can read in the files we wrote and sum up to the
    // same total number of elements.
    {
      MeshB mesh(*TestCommWorld);
      CheckpointIO cpr(mesh);
      cpr.binary() = binary;
      cpr.read(filename);

      std::size_t read_in_elements = 0;

      for (unsigned pid=mesh.processor_id(); pid<n_procs; pid += mesh.n_processors())
        {
          read_in_elements += std::distance(mesh.pid_elements_begin(pid),
                                            mesh.pid_elements_end(pid));
        }
      mesh.comm().sum(read_in_elements);

      // Verify that we read in exactly as many elements as we started with.
      CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(read_in_elements), original_n_elem);
    }
  }

  void testAsciiDistRepSplitter()
  {
    testSplitter<DistributedMesh, ReplicatedMesh>(false, true);
  }

  void testBinaryDistRepSplitter()
  {
    testSplitter<DistributedMesh, ReplicatedMesh>(true, true);
  }

  void testAsciiRepDistSplitter()
  {
    testSplitter<ReplicatedMesh, DistributedMesh>(false, true);
  }

  void testBinaryRepDistSplitter()
  {
    testSplitter<ReplicatedMesh, DistributedMesh>(true, true);
  }

  void testAsciiRepRepSplitter()
  {
    testSplitter<ReplicatedMesh, ReplicatedMesh>(false, false);
  }

  void testBinaryRepRepSplitter()
  {
    testSplitter<ReplicatedMesh, ReplicatedMesh>(true, false);
  }

  void testAsciiDistDistSplitter()
  {
    testSplitter<DistributedMesh, DistributedMesh>(false, true);
  }

  void testBinaryDistDistSplitter()
  {
    testSplitter<DistributedMesh, DistributedMesh>(true, true);
  }

};

CPPUNIT_TEST_SUITE_REGISTRATION( CheckpointIOTest );
<commit_msg>The CheckPointIO splitter unit tests require XDR.<commit_after>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include "libmesh/distributed_mesh.h"
#include "libmesh/replicated_mesh.h"
#include "libmesh/checkpoint_io.h"
#include "libmesh/mesh_generation.h"
#include "libmesh/partitioner.h"

#include "test_comm.h"

// THE CPPUNIT_TEST_SUITE_END macro expands to code that involves
// std::auto_ptr, which in turn produces -Wdeprecated-declarations
// warnings.  These can be ignored in GCC as long as we wrap the
// offending code in appropriate pragmas.  We can't get away with a
// single ignore_warnings.h inclusion at the beginning of this file,
// since the libmesh headers pull in a restore_warnings.h at some
// point.  We also don't bother restoring warnings at the end of this
// file since it's not a header.
#include <libmesh/ignore_warnings.h>

using namespace libMesh;

class CheckpointIOTest : public CppUnit::TestCase {
  /**
   * This test verifies that we can write files with the CheckpointIO object.
   */
public:
  CPPUNIT_TEST_SUITE( CheckpointIOTest );

  CPPUNIT_TEST( testAsciiDistRepSplitter );
  CPPUNIT_TEST( testBinaryDistRepSplitter );
  CPPUNIT_TEST( testAsciiRepDistSplitter );
  CPPUNIT_TEST( testBinaryRepDistSplitter );
  CPPUNIT_TEST( testAsciiRepRepSplitter );
  CPPUNIT_TEST( testBinaryRepRepSplitter );
  CPPUNIT_TEST( testAsciiDistDistSplitter );
  CPPUNIT_TEST( testBinaryDistDistSplitter );

  CPPUNIT_TEST_SUITE_END();

protected:

public:
  void setUp()
  {
  }

  void tearDown()
  {
  }

  // Test that we can write multiple checkpoint files from a single processor.
  template <typename MeshA, typename MeshB>
  void testSplitter(bool binary, bool using_distmesh)
  {
    // The CheckpointIO-based spltter requires XDR.
#ifdef LIBMESH_HAVE_XDR

    // In this test, we partition the mesh into n_procs parts.  Don't
    // try to partition a DistributedMesh into more parts than we have
    // processors, though.
    const unsigned int n_procs = using_distmesh ?
      std::min(static_cast<unsigned int>(2), TestCommWorld->size()) :
      2;

    // The number of elements in the original mesh.  For verification
    // later.
    dof_id_type original_n_elem = 0;

    const std::string filename =
      std::string("checkpoint_splitter.cp") + (binary ? "r" : "a");

    {
      MeshA mesh(*TestCommWorld);

      MeshTools::Generation::build_square(mesh,
                                          4,  4,
                                          0., 1.,
                                          0., 1.,
                                          QUAD4);

      // Store the number of elements that were in the original mesh.
      original_n_elem = mesh.n_elem();

      // Partition the mesh into n_procs pieces
      mesh.partition(n_procs);

      // Write out checkpoint files for each piece.  Since on a
      // ReplicatedMesh we might have more pieces than we do
      // processors, some processors may have to write out more than
      // one piece.
      CheckpointIO cpr(mesh);
      cpr.current_processor_ids().clear();
      for (processor_id_type pid = mesh.processor_id(); pid < n_procs; pid += mesh.n_processors())
        cpr.current_processor_ids().push_back(pid);
      cpr.current_n_processors() = n_procs;
      cpr.binary() = binary;
      cpr.parallel() = true;
      cpr.write(filename);
    }

    TestCommWorld->barrier();

    // Test that we can read in the files we wrote and sum up to the
    // same total number of elements.
    {
      MeshB mesh(*TestCommWorld);
      CheckpointIO cpr(mesh);
      cpr.binary() = binary;
      cpr.read(filename);

      std::size_t read_in_elements = 0;

      for (unsigned pid=mesh.processor_id(); pid<n_procs; pid += mesh.n_processors())
        {
          read_in_elements += std::distance(mesh.pid_elements_begin(pid),
                                            mesh.pid_elements_end(pid));
        }
      mesh.comm().sum(read_in_elements);

      // Verify that we read in exactly as many elements as we started with.
      CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(read_in_elements), original_n_elem);
    }
#endif // LIBMESH_HAVE_XDR
  }

  void testAsciiDistRepSplitter()
  {
    testSplitter<DistributedMesh, ReplicatedMesh>(false, true);
  }

  void testBinaryDistRepSplitter()
  {
    testSplitter<DistributedMesh, ReplicatedMesh>(true, true);
  }

  void testAsciiRepDistSplitter()
  {
    testSplitter<ReplicatedMesh, DistributedMesh>(false, true);
  }

  void testBinaryRepDistSplitter()
  {
    testSplitter<ReplicatedMesh, DistributedMesh>(true, true);
  }

  void testAsciiRepRepSplitter()
  {
    testSplitter<ReplicatedMesh, ReplicatedMesh>(false, false);
  }

  void testBinaryRepRepSplitter()
  {
    testSplitter<ReplicatedMesh, ReplicatedMesh>(true, false);
  }

  void testAsciiDistDistSplitter()
  {
    testSplitter<DistributedMesh, DistributedMesh>(false, true);
  }

  void testBinaryDistDistSplitter()
  {
    testSplitter<DistributedMesh, DistributedMesh>(true, true);
  }

};

CPPUNIT_TEST_SUITE_REGISTRATION( CheckpointIOTest );
<|endoftext|>


<commit_before>/*
 * KeyListOps.cpp
 *
 *  Created on: Feb 24, 2014
 *      Author: nek3d
 */
#include "KeyListOps.h"
#include "FileRecordMgr.h"
#include <cmath> //for isnan
#include <sstream>
#include <iomanip>

KeyListOps::KeyListOps():
_dbFileType(FileRecordTypeChecker::UNKNOWN_FILE_TYPE)
{
	_opCodes["sum"] = SUM;
	_opCodes["mean"] = MEAN;
	_opCodes["stdev"] = STDDEV;
	_opCodes["sstdev"] = SAMPLE_STDDEV;
	_opCodes["median"] = MEDIAN;
	_opCodes["mode"] = MODE;
	_opCodes["antimode"] = ANTIMODE;
	_opCodes["min"] = MIN;
	_opCodes["max"] = MAX;
	_opCodes["absmin"] = ABSMIN;
	_opCodes["absmax"] = ABSMAX;
	_opCodes["count"] = COUNT;
	_opCodes["distinct"] = DISTINCT;
	_opCodes["count_distinct"] = COUNT_DISTINCT;
	_opCodes["distinct_only"] = DISTINCT_ONLY;
	_opCodes["distinct_sort_num"] = DISTINCT_SORT_NUM;
	_opCodes["distinct_sort_num_desc"] = DISTINCT_SORT_NUM_DESC;

	_opCodes["collapse"] = COLLAPSE;
	_opCodes["concat"] = CONCAT;
	_opCodes["freqasc"] = FREQ_ASC;
	_opCodes["freqdesc"] = FREQ_DESC;
	_opCodes["first"] = FIRST;
	_opCodes["last"] = LAST;

	_isNumericOp[SUM] = true;
	_isNumericOp[MEAN] = true;
	_isNumericOp[STDDEV] = true;
	_isNumericOp[MEDIAN] = true;
	_isNumericOp[MODE] = false;
	_isNumericOp[ANTIMODE] = false;
	_isNumericOp[MIN] = true;
	_isNumericOp[MAX] = true;
	_isNumericOp[ABSMIN] = true;
	_isNumericOp[COUNT] = false;
	_isNumericOp[DISTINCT] = false;
	_isNumericOp[COUNT_DISTINCT] = false;
	_isNumericOp[DISTINCT_ONLY] = false;
	_isNumericOp[COLLAPSE] = false;
	_isNumericOp[CONCAT] = false;
	_isNumericOp[FREQ_ASC] = false;
	_isNumericOp[FREQ_DESC] = false;
	_isNumericOp[FIRST] = false;
	_isNumericOp[LAST] = false;

	_methods.setDelimStr(",");
	_methods.setNullValue(".");

	// default to BED score column
	_columns = "5";
	// default to "sum"
	_operations = "sum";
	_precision = DEFAULT_PRECISION;

}

bool KeyListOps::isNumericOp(OP_TYPES op) const {
	map<OP_TYPES, bool>::const_iterator iter = _isNumericOp.find(op);
	return (iter == _isNumericOp.end() ? false : iter->second);
}

bool KeyListOps::isNumericOp(const string &op) const {
	return isNumericOp(getOpCode(op));
}

KeyListOps::OP_TYPES KeyListOps::getOpCode(const string &operation) const {
	//If the operation does not exist, return INVALID.
	//otherwise, return code for given operation.
	map<string, OP_TYPES>::const_iterator iter = _opCodes.find(operation);
	if (iter == _opCodes.end()) {
		return INVALID;
	}
	return iter->second;
}

bool KeyListOps::isValidColumnOps(FileRecordMgr *dbFile) {

	//get the strings from context containing the comma-delimited lists of columns
	//and operations. Split both of these into vectors. Get the operation code
	//for each operation string. Finally, make a vector of pairs, where the first
	//member of each pair is a column number, and the second member is the code for the
	//operation to perform on that column.

    Tokenizer colTokens;
    Tokenizer opsTokens;

    int numCols = colTokens.tokenize(_columns, ',');
	int numOps = opsTokens.tokenize(_operations, ',');

	if (numOps < 1 || numCols < 1) {
		 cerr << endl << "*****" << endl
		             << "***** ERROR: There must be at least one column and at least one operation named." << endl;
		 return false;
	}
	if (numOps > 1 && numCols > 1 && numCols != numOps) {
		 cerr << endl << "*****" << endl
		             << "***** ERROR: There are " << numCols <<" columns given, but there are " << numOps << " operations." << endl;
		cerr << "\tPlease provide either a single operation that will be applied to all listed columns, " << endl;
		cerr << "\ta single column to which all operations will be applied," << endl;
		cerr << "\tor an operation for each column." << endl;
		return false;
	}
	int loop = max(numCols, numOps);

	// If there is only one column, all ops are performed on it.
	// Otherwise, if there is only op, it is performed on all columns.
	// Besides that, ops are performed on columns in their respective
	// ordering.

	for (int i=0; i < loop; i++) {
		int col = str2chrPos(colTokens.getElem(numCols > 1 ? i : 0));

		//check that the column number is valid
		if (col < 1 || col > dbFile->getNumFields()) {
			 cerr << endl << "*****" << endl  << "***** ERROR: Requested column " << col << ", but database file "
					 << dbFile->getFileName() << " only has fields 1 - " << dbFile->getNumFields() << "." << endl;
			 return false;
		}
		const string &operation = opsTokens.getElem(numOps > 1 ? i : 0);
		OP_TYPES opCode = getOpCode(operation);
		if (opCode == INVALID) {
			cerr << endl << "*****" << endl
								 << "***** ERROR: " << operation << " is not a valid operation. " << endl;
			return false;
		}
		_colOps.push_back(pair<int, OP_TYPES>(col, opCode));
	}

	//lastly, if the file is BAM, and they asked for column 2, which is the
	//flags field, then for now we have to throw an error, as the flag field
	//is currently not supported.
	if (_dbFileType == FileRecordTypeChecker::BAM_FILE_TYPE) {
		//also, tell the methods class we're dealing with BAM.
		_methods.setIsBam(true);
		for (size_t i = 0; i < _colOps.size(); i++) {
			if (_colOps[i].first == 2) {
				cerr << endl << "*****" << endl << "***** ERROR: Requested column 2 of a BAM file, which is the Flags field." << endl;
				cerr << "             We currently do not support this, but may in future versions." << endl;
				return false;
			}
		}
	}

    return true;
}

const string & KeyListOps::getOpVals(RecordKeyVector &hits)
{
	//loop through all requested columns, and for each one, call the method needed
	//for the operation specified.
	_methods.setKeyList(&hits);
	_outVals.clear();
	double val = 0.0;
	for (int i=0; i < (int)_colOps.size(); i++) {
		ostringstream s;
		int col = _colOps[i].first;
		OP_TYPES opCode = _colOps[i].second;

		_methods.setColumn(col);
		switch (opCode) {
		case SUM:
			val = _methods.getSum();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MEAN:
			val = _methods.getMean();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case STDDEV:
			val = _methods.getStddev();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case SAMPLE_STDDEV:
			val = _methods.getSampleStddev();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MEDIAN:
			val = _methods.getMedian();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MODE:
			s << _methods.getMode();
			break;

		case ANTIMODE:
			s << _methods.getAntiMode();
			break;

		case MIN:
			val = _methods.getMin();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MAX:
			val = _methods.getMax();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case ABSMIN:
			val = _methods.getAbsMin();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case ABSMAX:
			val = _methods.getAbsMax();
			if (isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case COUNT:
			s << _methods.getCount();
			break;

		case DISTINCT:
			s << _methods.getDistinct();
			break;

		case DISTINCT_SORT_NUM:
			s << _methods.getDistinctSortNum();
			break;

		case DISTINCT_SORT_NUM_DESC:
			s << _methods.getDistinctSortNum(false);
			break;

		case COUNT_DISTINCT:
			s << _methods.getCountDistinct();
			break;

		case DISTINCT_ONLY:
			s << _methods.getDistinctOnly();
			break;

		case COLLAPSE:
			s << _methods.getCollapse();
			break;

		case CONCAT:
			s << _methods.getConcat();
			break;

		case FREQ_ASC:
			s << _methods.getFreqAsc();
			break;

		case FREQ_DESC:
			s << _methods.getFreqDesc();
			break;

		case FIRST:
			s << _methods.getFirst();
			break;

		case LAST:
			s << _methods.getLast();
			break;

		case INVALID:
		default:
			// Any unrecognized operation should have been handled already in the context validation.
			// It's thus unnecessary to handle it here, but throw an error to help us know if future
			// refactoring or code changes accidentally bypass the validation phase.
			cerr << "ERROR: Invalid operation given for column " << col << ". Exiting..." << endl;
			break;
		}
		_outVals.append(s.str());
		//if this isn't the last column, add a tab.
		if (i < (int)_colOps.size() -1) {
			_outVals.append("\t");
		}
	}
	if (_methods.nonNumErrFlagSet()) {
		//asked for a numeric op on a column in which a non numeric value was found.
		cerr << _methods.getErrMsg() << endl;
		_methods.resetNonNumErrFlag();
	}
	return _outVals;
}

const string &KeyListOps::format(double val)
{
   std::stringstream strmBuf;
   strmBuf << std::setprecision (_precision) << val;
   _formatStr = strmBuf.str();
   return _formatStr;
}

void KeyListOpsHelp() {

    cerr << "\t-c\t"             << "Specify columns from the B file to map onto intervals in A." << endl;
    cerr                         << "\t\tDefault: 5." << endl;
    cerr						<<  "\t\tMultiple columns can be specified in a comma-delimited list." << endl << endl;

    cerr << "\t-o\t"             << "Specify the operation that should be applied to -c." << endl;
    cerr                         << "\t\tValid operations:" << endl;
    cerr                         << "\t\t    sum, min, max, absmin, absmax," << endl;
    cerr                         << "\t\t    mean, median, mode, antimode" << endl;
    cerr                         << "\t\t    stdev, sstdev" << endl;
    cerr                         << "\t\t    collapse (i.e., print a delimited list (duplicates allowed)), " << endl;
    cerr                         << "\t\t    distinct (i.e., print a delimited list (NO duplicates allowed)), " << endl;
    cerr                         << "\t\t    distinct_sort_num (as distinct, sorted numerically, ascending)," << endl;
    cerr                         << "\t\t    distinct_sort_num_desc (as distinct, sorted numerically, desscending)," << endl;
    cerr                         << "\t\t    distinct_only (delimited list of only unique values)," << endl;
    cerr                         << "\t\t    count" << endl;
    cerr                         << "\t\t    count_distinct (i.e., a count of the unique values in the column), " << endl;
    cerr                         << "\t\t    first (i.e., just the first value in the column), " << endl;
    cerr                         << "\t\t    last (i.e., just the last value in the column), " << endl;
    cerr                         << "\t\tDefault: sum" << endl;
    cerr						 << "\t\tMultiple operations can be specified in a comma-delimited list." << endl << endl;

    cerr						<< "\t\tIf there is only column, but multiple operations, all operations will be" << endl;
    cerr						<< "\t\tapplied on that column. Likewise, if there is only one operation, but" << endl;
    cerr						<< "\t\tmultiple columns, that operation will be applied to all columns." << endl;
    cerr						<< "\t\tOtherwise, the number of columns must match the the number of operations," << endl;
    cerr						<< "\t\tand will be applied in respective order." << endl;
    cerr						<< "\t\tE.g., \"-c 5,4,6 -o sum,mean,count\" will give the sum of column 5," << endl;
    cerr						<< "\t\tthe mean of column 4, and the count of column 6." << endl;
    cerr						<< "\t\tThe order of output columns will match the ordering given in the command." << endl << endl<<endl;

    cerr << "\t-delim\t"                 << "Specify a custom delimiter for the collapse operations." << endl;
    cerr                                 << "\t\t- Example: -delim \"|\"" << endl;
    cerr                                 << "\t\t- Default: \",\"." << endl << endl;

    cerr << "\t-prec\t"   		 << "Sets the decimal precision for output (Default: 5)" << endl << endl;
}
<commit_msg>specified which version of isnan to use in KeyListOps<commit_after>/*
 * KeyListOps.cpp
 *
 *  Created on: Feb 24, 2014
 *      Author: nek3d
 */
#include "KeyListOps.h"
#include "FileRecordMgr.h"
#include <cmath> //for std::isnan
#include <sstream>
#include <iomanip>

KeyListOps::KeyListOps():
_dbFileType(FileRecordTypeChecker::UNKNOWN_FILE_TYPE)
{
	_opCodes["sum"] = SUM;
	_opCodes["mean"] = MEAN;
	_opCodes["stdev"] = STDDEV;
	_opCodes["sstdev"] = SAMPLE_STDDEV;
	_opCodes["median"] = MEDIAN;
	_opCodes["mode"] = MODE;
	_opCodes["antimode"] = ANTIMODE;
	_opCodes["min"] = MIN;
	_opCodes["max"] = MAX;
	_opCodes["absmin"] = ABSMIN;
	_opCodes["absmax"] = ABSMAX;
	_opCodes["count"] = COUNT;
	_opCodes["distinct"] = DISTINCT;
	_opCodes["count_distinct"] = COUNT_DISTINCT;
	_opCodes["distinct_only"] = DISTINCT_ONLY;
	_opCodes["distinct_sort_num"] = DISTINCT_SORT_NUM;
	_opCodes["distinct_sort_num_desc"] = DISTINCT_SORT_NUM_DESC;

	_opCodes["collapse"] = COLLAPSE;
	_opCodes["concat"] = CONCAT;
	_opCodes["freqasc"] = FREQ_ASC;
	_opCodes["freqdesc"] = FREQ_DESC;
	_opCodes["first"] = FIRST;
	_opCodes["last"] = LAST;

	_isNumericOp[SUM] = true;
	_isNumericOp[MEAN] = true;
	_isNumericOp[STDDEV] = true;
	_isNumericOp[MEDIAN] = true;
	_isNumericOp[MODE] = false;
	_isNumericOp[ANTIMODE] = false;
	_isNumericOp[MIN] = true;
	_isNumericOp[MAX] = true;
	_isNumericOp[ABSMIN] = true;
	_isNumericOp[COUNT] = false;
	_isNumericOp[DISTINCT] = false;
	_isNumericOp[COUNT_DISTINCT] = false;
	_isNumericOp[DISTINCT_ONLY] = false;
	_isNumericOp[COLLAPSE] = false;
	_isNumericOp[CONCAT] = false;
	_isNumericOp[FREQ_ASC] = false;
	_isNumericOp[FREQ_DESC] = false;
	_isNumericOp[FIRST] = false;
	_isNumericOp[LAST] = false;

	_methods.setDelimStr(",");
	_methods.setNullValue(".");

	// default to BED score column
	_columns = "5";
	// default to "sum"
	_operations = "sum";
	_precision = DEFAULT_PRECISION;

}

bool KeyListOps::isNumericOp(OP_TYPES op) const {
	map<OP_TYPES, bool>::const_iterator iter = _isNumericOp.find(op);
	return (iter == _isNumericOp.end() ? false : iter->second);
}

bool KeyListOps::isNumericOp(const string &op) const {
	return isNumericOp(getOpCode(op));
}

KeyListOps::OP_TYPES KeyListOps::getOpCode(const string &operation) const {
	//If the operation does not exist, return INVALID.
	//otherwise, return code for given operation.
	map<string, OP_TYPES>::const_iterator iter = _opCodes.find(operation);
	if (iter == _opCodes.end()) {
		return INVALID;
	}
	return iter->second;
}

bool KeyListOps::isValidColumnOps(FileRecordMgr *dbFile) {

	//get the strings from context containing the comma-delimited lists of columns
	//and operations. Split both of these into vectors. Get the operation code
	//for each operation string. Finally, make a vector of pairs, where the first
	//member of each pair is a column number, and the second member is the code for the
	//operation to perform on that column.

    Tokenizer colTokens;
    Tokenizer opsTokens;

    int numCols = colTokens.tokenize(_columns, ',');
	int numOps = opsTokens.tokenize(_operations, ',');

	if (numOps < 1 || numCols < 1) {
		 cerr << endl << "*****" << endl
		             << "***** ERROR: There must be at least one column and at least one operation named." << endl;
		 return false;
	}
	if (numOps > 1 && numCols > 1 && numCols != numOps) {
		 cerr << endl << "*****" << endl
		             << "***** ERROR: There are " << numCols <<" columns given, but there are " << numOps << " operations." << endl;
		cerr << "\tPlease provide either a single operation that will be applied to all listed columns, " << endl;
		cerr << "\ta single column to which all operations will be applied," << endl;
		cerr << "\tor an operation for each column." << endl;
		return false;
	}
	int loop = max(numCols, numOps);

	// If there is only one column, all ops are performed on it.
	// Otherwise, if there is only op, it is performed on all columns.
	// Besides that, ops are performed on columns in their respective
	// ordering.

	for (int i=0; i < loop; i++) {
		int col = str2chrPos(colTokens.getElem(numCols > 1 ? i : 0));

		//check that the column number is valid
		if (col < 1 || col > dbFile->getNumFields()) {
			 cerr << endl << "*****" << endl  << "***** ERROR: Requested column " << col << ", but database file "
					 << dbFile->getFileName() << " only has fields 1 - " << dbFile->getNumFields() << "." << endl;
			 return false;
		}
		const string &operation = opsTokens.getElem(numOps > 1 ? i : 0);
		OP_TYPES opCode = getOpCode(operation);
		if (opCode == INVALID) {
			cerr << endl << "*****" << endl
								 << "***** ERROR: " << operation << " is not a valid operation. " << endl;
			return false;
		}
		_colOps.push_back(pair<int, OP_TYPES>(col, opCode));
	}

	//lastly, if the file is BAM, and they asked for column 2, which is the
	//flags field, then for now we have to throw an error, as the flag field
	//is currently not supported.
	if (_dbFileType == FileRecordTypeChecker::BAM_FILE_TYPE) {
		//also, tell the methods class we're dealing with BAM.
		_methods.setIsBam(true);
		for (size_t i = 0; i < _colOps.size(); i++) {
			if (_colOps[i].first == 2) {
				cerr << endl << "*****" << endl << "***** ERROR: Requested column 2 of a BAM file, which is the Flags field." << endl;
				cerr << "             We currently do not support this, but may in future versions." << endl;
				return false;
			}
		}
	}

    return true;
}

const string & KeyListOps::getOpVals(RecordKeyVector &hits)
{
	//loop through all requested columns, and for each one, call the method needed
	//for the operation specified.
	_methods.setKeyList(&hits);
	_outVals.clear();
	double val = 0.0;
	for (int i=0; i < (int)_colOps.size(); i++) {
		ostringstream s;
		int col = _colOps[i].first;
		OP_TYPES opCode = _colOps[i].second;

		_methods.setColumn(col);
		switch (opCode) {
		case SUM:
			val = _methods.getSum();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MEAN:
			val = _methods.getMean();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case STDDEV:
			val = _methods.getStddev();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case SAMPLE_STDDEV:
			val = _methods.getSampleStddev();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MEDIAN:
			val = _methods.getMedian();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MODE:
			s << _methods.getMode();
			break;

		case ANTIMODE:
			s << _methods.getAntiMode();
			break;

		case MIN:
			val = _methods.getMin();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case MAX:
			val = _methods.getMax();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case ABSMIN:
			val = _methods.getAbsMin();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case ABSMAX:
			val = _methods.getAbsMax();
			if (std::isnan(val)) {
				s << _methods.getNullValue();
			} else {
				s << format(val);
			}
			break;

		case COUNT:
			s << _methods.getCount();
			break;

		case DISTINCT:
			s << _methods.getDistinct();
			break;

		case DISTINCT_SORT_NUM:
			s << _methods.getDistinctSortNum();
			break;

		case DISTINCT_SORT_NUM_DESC:
			s << _methods.getDistinctSortNum(false);
			break;

		case COUNT_DISTINCT:
			s << _methods.getCountDistinct();
			break;

		case DISTINCT_ONLY:
			s << _methods.getDistinctOnly();
			break;

		case COLLAPSE:
			s << _methods.getCollapse();
			break;

		case CONCAT:
			s << _methods.getConcat();
			break;

		case FREQ_ASC:
			s << _methods.getFreqAsc();
			break;

		case FREQ_DESC:
			s << _methods.getFreqDesc();
			break;

		case FIRST:
			s << _methods.getFirst();
			break;

		case LAST:
			s << _methods.getLast();
			break;

		case INVALID:
		default:
			// Any unrecognized operation should have been handled already in the context validation.
			// It's thus unnecessary to handle it here, but throw an error to help us know if future
			// refactoring or code changes accidentally bypass the validation phase.
			cerr << "ERROR: Invalid operation given for column " << col << ". Exiting..." << endl;
			break;
		}
		_outVals.append(s.str());
		//if this isn't the last column, add a tab.
		if (i < (int)_colOps.size() -1) {
			_outVals.append("\t");
		}
	}
	if (_methods.nonNumErrFlagSet()) {
		//asked for a numeric op on a column in which a non numeric value was found.
		cerr << _methods.getErrMsg() << endl;
		_methods.resetNonNumErrFlag();
	}
	return _outVals;
}

const string &KeyListOps::format(double val)
{
   std::stringstream strmBuf;
   strmBuf << std::setprecision (_precision) << val;
   _formatStr = strmBuf.str();
   return _formatStr;
}

void KeyListOpsHelp() {

    cerr << "\t-c\t"             << "Specify columns from the B file to map onto intervals in A." << endl;
    cerr                         << "\t\tDefault: 5." << endl;
    cerr						<<  "\t\tMultiple columns can be specified in a comma-delimited list." << endl << endl;

    cerr << "\t-o\t"             << "Specify the operation that should be applied to -c." << endl;
    cerr                         << "\t\tValid operations:" << endl;
    cerr                         << "\t\t    sum, min, max, absmin, absmax," << endl;
    cerr                         << "\t\t    mean, median, mode, antimode" << endl;
    cerr                         << "\t\t    stdev, sstdev" << endl;
    cerr                         << "\t\t    collapse (i.e., print a delimited list (duplicates allowed)), " << endl;
    cerr                         << "\t\t    distinct (i.e., print a delimited list (NO duplicates allowed)), " << endl;
    cerr                         << "\t\t    distinct_sort_num (as distinct, sorted numerically, ascending)," << endl;
    cerr                         << "\t\t    distinct_sort_num_desc (as distinct, sorted numerically, desscending)," << endl;
    cerr                         << "\t\t    distinct_only (delimited list of only unique values)," << endl;
    cerr                         << "\t\t    count" << endl;
    cerr                         << "\t\t    count_distinct (i.e., a count of the unique values in the column), " << endl;
    cerr                         << "\t\t    first (i.e., just the first value in the column), " << endl;
    cerr                         << "\t\t    last (i.e., just the last value in the column), " << endl;
    cerr                         << "\t\tDefault: sum" << endl;
    cerr						 << "\t\tMultiple operations can be specified in a comma-delimited list." << endl << endl;

    cerr						<< "\t\tIf there is only column, but multiple operations, all operations will be" << endl;
    cerr						<< "\t\tapplied on that column. Likewise, if there is only one operation, but" << endl;
    cerr						<< "\t\tmultiple columns, that operation will be applied to all columns." << endl;
    cerr						<< "\t\tOtherwise, the number of columns must match the the number of operations," << endl;
    cerr						<< "\t\tand will be applied in respective order." << endl;
    cerr						<< "\t\tE.g., \"-c 5,4,6 -o sum,mean,count\" will give the sum of column 5," << endl;
    cerr						<< "\t\tthe mean of column 4, and the count of column 6." << endl;
    cerr						<< "\t\tThe order of output columns will match the ordering given in the command." << endl << endl<<endl;

    cerr << "\t-delim\t"                 << "Specify a custom delimiter for the collapse operations." << endl;
    cerr                                 << "\t\t- Example: -delim \"|\"" << endl;
    cerr                                 << "\t\t- Default: \",\"." << endl << endl;

    cerr << "\t-prec\t"   		 << "Sets the decimal precision for output (Default: 5)" << endl << endl;
}
<|endoftext|>


<commit_before>/*!
 * \file hyo_utilities_tests.cpp
 * \author Robert 'Bob' Caddy (rvc@pitt.edu), Helena Richie (helenarichie@pitt.edu)
 * \brief Tests for the contents of hydro_utilities.h and hydro_utilities.cpp
 *
 */

// STL Includes
#include <vector>
#include <string>
#include <iostream>

// External Includes
#include <gtest/gtest.h>    // Include GoogleTest and related libraries/headers

// Local Includes
#include "../utils/testing_utilities.h"
#include "../utils/hydro_utilities.h"
#include "../global/global.h"

/*!
* INDEX OF VARIABLES
* P : pressure
* vx, vy, vz : x, y, and z velocity
* d : density
* E : energy
* T : temperature
* mx, my, mz : x, y, and z momentum
* n : number density
*/

// =============================================================================
// Local helper functions

namespace
{
    struct TestParams
    {
        double gamma = 5./3.;
        std::vector<double> d {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<double> vx {1.0378624601e-100, 1.0829278656e2, 1.0800514112e100};
        std::vector<double> vy {1.0583469014e-100, 1.0283073464e2, 1.0725717864e100};
        std::vector<double> vz {1.0182972216e-100, 1.0417748226e2, 1.0855352639e100};
        std::vector<double> mx {0.2340416681e-100, 0.1019429453e2, 0.5062596954e100};
        std::vector<double> my {0.9924582299e-100, 0.1254780684e2, 0.5939640992e100};
        std::vector<double> mz {0.6703192739e-100, 0.5676716066e2, 0.2115881803e100};
        std::vector<double> E {20.9342082433e-90, 20.9976906577e10, 20.9487120853e300};
        std::vector<double> P {2.2244082909e-100, 8.6772951021e2, 6.7261085663e100};
        std::vector<double> n {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<double> ge {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<std::string> names{"Small number case", "Medium number case", "Large number case"};
    };
}

TEST(tHYDROSYSTEMHydroUtilsCalcPressurePrimitive, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ps {1e-20, 139983415580.5549, 1.2697896247496674e+301};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ps = hydro_utilities::Calc_Pressure_Primitive(parameters.E.at(i), parameters.d.at(i), parameters.vx.at(i), parameters.vy.at(i), parameters.vz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Ps.at(i), test_Ps, parameters.names.at(i));
    }
}

TEST(tHYDROSYSTEMHydroUtilsCalcPressureConserved, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ps {1e-20, 139984604373.87094, 1.3965808056866668e+301};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ps = hydro_utilities::Calc_Pressure_Conserved(parameters.E.at(i), parameters.d.at(i), parameters.mx.at(i), parameters.my.at(i), parameters.mz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Ps.at(i), test_Ps, parameters.names.at(i));
    }
}

TEST(tHYDROSYSTEMHydroUtilsCalcTemp, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ts {10335643.97340712, 37808388.612783447, 28968949.83344138};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ts = hydro_utilities::Calc_Temp(parameters.P.at(i), parameters.n.at(i));

        testingUtilities::checkResults(fiducial_Ts.at(i), test_Ts, parameters.names.at(i));
    }
}

#ifdef DE
TEST(tHYDROSYSTEMHydroUtilsCalcTempDE, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ts {3.1519051484164999e-94, 336118467.45898658, 3.4003787759209402e+106};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ts = hydro_utilities::Calc_Temp_DE(parameters.d.at(i), parameters.ge.at(i), parameters.gamma, parameters.n.at(i));

        testingUtilities::checkResults(fiducial_Ts.at(i), test_Ts, parameters.names.at(i));
    }
}
#endif // DE

TEST(tHYDROSYSTEMHydroUtilsCalcEnergyPrimitive, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Es {3.1519051484164999e-94, 336118467.45898658, 3.4003787759209402e+106};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Es = hydro_utilities::Calc_Energy_Primitive(parameters.P.at(i), parameters.d.at(i), parameters.vx.at(i), parameters.vy.at(i), parameters.vz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Es.at(i), test_Es, parameters.names.at(i));
    }
}<commit_msg>add test for primitive energy  utility function<commit_after>/*!
 * \file hyo_utilities_tests.cpp
 * \author Robert 'Bob' Caddy (rvc@pitt.edu), Helena Richie (helenarichie@pitt.edu)
 * \brief Tests for the contents of hydro_utilities.h and hydro_utilities.cpp
 *
 */

// STL Includes
#include <vector>
#include <string>
#include <iostream>

// External Includes
#include <gtest/gtest.h>    // Include GoogleTest and related libraries/headers

// Local Includes
#include "../utils/testing_utilities.h"
#include "../utils/hydro_utilities.h"
#include "../global/global.h"

/*!
* INDEX OF VARIABLES
* P : pressure
* vx, vy, vz : x, y, and z velocity
* d : density
* E : energy
* T : temperature
* mx, my, mz : x, y, and z momentum
* n : number density
*/

// =============================================================================
// Local helper functions

namespace
{
    struct TestParams
    {
        double gamma = 5./3.;
        std::vector<double> d {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<double> vx {1.0378624601e-100, 1.0829278656e2, 1.0800514112e100};
        std::vector<double> vy {1.0583469014e-100, 1.0283073464e2, 1.0725717864e100};
        std::vector<double> vz {1.0182972216e-100, 1.0417748226e2, 1.0855352639e100};
        std::vector<double> mx {0.2340416681e-100, 0.1019429453e2, 0.5062596954e100};
        std::vector<double> my {0.9924582299e-100, 0.1254780684e2, 0.5939640992e100};
        std::vector<double> mz {0.6703192739e-100, 0.5676716066e2, 0.2115881803e100};
        std::vector<double> E {20.9342082433e-90, 20.9976906577e10, 20.9487120853e300};
        std::vector<double> P {2.2244082909e-100, 8.6772951021e2, 6.7261085663e100};
        std::vector<double> n {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<double> ge {1.0087201154e-100, 1.0756968986e2, 1.0882403847e100};
        std::vector<std::string> names{"Small number case", "Medium number case", "Large number case"};
    };
}

TEST(tHYDROSYSTEMHydroUtilsCalcPressurePrimitive, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ps {1e-20, 139983415580.5549, 1.2697896247496674e+301};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ps = hydro_utilities::Calc_Pressure_Primitive(parameters.E.at(i), parameters.d.at(i), parameters.vx.at(i), parameters.vy.at(i), parameters.vz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Ps.at(i), test_Ps, parameters.names.at(i));
    }
}

TEST(tHYDROSYSTEMHydroUtilsCalcPressureConserved, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ps {1e-20, 139984604373.87094, 1.3965808056866668e+301};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ps = hydro_utilities::Calc_Pressure_Conserved(parameters.E.at(i), parameters.d.at(i), parameters.mx.at(i), parameters.my.at(i), parameters.mz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Ps.at(i), test_Ps, parameters.names.at(i));
    }
}

TEST(tHYDROSYSTEMHydroUtilsCalcTemp, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ts {10335643.97340712, 37808388.612783447, 28968949.83344138};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ts = hydro_utilities::Calc_Temp(parameters.P.at(i), parameters.n.at(i));

        testingUtilities::checkResults(fiducial_Ts.at(i), test_Ts, parameters.names.at(i));
    }
}

#ifdef DE
TEST(tHYDROSYSTEMHydroUtilsCalcTempDE, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Ts {3.1519051484164999e-94, 336118467.45898658, 3.4003787759209402e+106};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Ts = hydro_utilities::Calc_Temp_DE(parameters.d.at(i), parameters.ge.at(i), parameters.gamma, parameters.n.at(i));

        testingUtilities::checkResults(fiducial_Ts.at(i), test_Ts, parameters.names.at(i));
    }
}
#endif // DE

TEST(tHYDROSYSTEMHydroUtilsCalcEnergyPrimitive, CorrectInputExpectCorrectOutput) {
    TestParams parameters;
    std::vector<double> fiducial_Es {3.1519051484164999e-94, 1784507.7619407175, 1.9018677140549926e+300};

    for (size_t i = 0; i < parameters.names.size(); i++)
    {
        Real test_Es = hydro_utilities::Calc_Energy_Primitive(parameters.P.at(i), parameters.d.at(i), parameters.vx.at(i), parameters.vy.at(i), parameters.vz.at(i), parameters.gamma);

        testingUtilities::checkResults(fiducial_Es.at(i), test_Es, parameters.names.at(i));
    }
}<|endoftext|>