<commit_before>#ifndef COBALT_EVENTS_HPP_INCLUDED
#define COBALT_EVENTS_HPP_INCLUDED

#pragma once

// Classes in this file:
//     event
//     basic_event
//     rebind_event_handler
//     event_dispatcher
//     event_subscriber
//     event_target

#include <cobalt/utility/intrusive.hpp>
#include <cobalt/utility/hash.hpp>
#include <cobalt/utility/enum_traits.hpp>

#include <boost/assert.hpp>

#include <array>
#include <deque>
#include <unordered_map>
#include <chrono>

CO_DEFINE_ENUM_CLASS(
	event_phase, uint8_t,
	bubbling,
	capture,
	sinking
)

CO_DEFINE_ENUM_FLAGS_CLASS(
	subscribe_mode, uint8_t,
	type = 1 << 0,
	name = 1 << 1,
	type_and_name = type | name
)

namespace cobalt {

/// event
class event : public ref_counter<event> {
public:
	typedef hash_type target_type;

	virtual ~event() = default;
	virtual target_type target() const = 0;
};

/// basic_event
template <event::target_type Target>
class basic_event : public event {
public:
	static constexpr target_type type = Target;

	virtual target_type target() const override { return Target; }
};

#define CO_DEFINE_EVENT_CLASS(event_class_name) class event_class_name : public basic_event<#event_class_name##_hash>

/// rebind_event_handler
template
<
	typename T,
	typename E,
	typename = typename std::enable_if<std::is_base_of<event, E>::value>::type
>
class rebind_event_handler {
public:
	rebind_event_handler(void(T::*mf)(E*), T* obj)
		: _obj(obj)
		, _mf(mf)
	{
	}

	void operator()(event* ev) {
		(_obj->*_mf)(static_cast<E*>(ev));
	}

	friend bool operator==(const rebind_event_handler& rhs, const rebind_event_handler& lhs) {
		return rhs._obj == lhs._obj && rhs._mf == lhs._mf;
	}

private:
	T* _obj;
	void(T::*_mf)(E*);
};

/// event_dispatcher
class event_dispatcher {
public:
	typedef event::target_type target_type;
	typedef std::function<void(event*)> handler_type;
	typedef std::chrono::high_resolution_clock clock_type;

	event_dispatcher() = default;

	// subscribe/subscribed/unsubscribe

	size_t subscribe(target_type target, handler_type handler) {
		size_t handler_hash = handler.target_type().hash_code();
		_handlers.emplace(target, std::move(handler));
		return handler_hash;
	}

	bool subscribed(target_type target, handler_type handler) const {
		return subscribed(target, handler.target_type().hash_code());
	}

	bool subscribed(target_type target, size_t handler_hash) const {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash)
				return true;
		}
		return false;
	}

	bool unsubscribe(target_type target, handler_type handler) {
		return unsubscribe(target, handler.target_type().hash_code());
	}

	bool unsubscribe(target_type target, size_t handler_hash) {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash) {
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// subscribe/subscribed/unsubscribe templated overloads for member functions

	template <typename T, typename E>
	size_t subscribe(void(T::*mf)(E*), T* obj) {
		subscribe(E::type, rebind_event_handler<T, E>(mf, obj));
		return typeid(rebind_event_handler<T, E>).hash_code();
	}

	template <typename T, typename E>
	bool subscribed(void(T::*mf)(E*), T* obj) const {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj))
				return true;
		}
		return false;
	}

	template <typename T, typename E>
	bool unsubscribe(void(T::*mf)(E*), T* obj, size_t* handler_hash = nullptr) {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj)) {
				if (handler_hash)
					*handler_hash = (*it).second.target_type().hash_code();
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// post/dispatch/invoke

	bool empty() const {
		return _queues[0].empty();
	}

	void post(const ref_ptr<event>& event) {
		_queues[0].emplace_back(event->target(), event);
	}

	void post(ref_ptr<event>&& event) {
		_queues[0].emplace_back(event->target(), std::move(event));
	}

	void post(target_type target, const ref_ptr<event>& event) {
		_queues[0].emplace_back(target, event);
	}

	void post(target_type target, ref_ptr<event>&& event) {
		_queues[0].emplace_back(target, std::move(event));
	}

	bool posted(target_type target) const {
		for (auto&& p : _queues[0]) {
			if (p.first == target)
				return true;
		}
		return false;
	}

	bool abort_first(target_type target) {
		auto it = std::find_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end()) {
			_queues[0].erase(it);
			return true;
		}

		return false;
	}

	bool abort_last(target_type target) {
		auto it = std::find_if(_queues[0].rbegin(), _queues[0].rend(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].rend()) {
			_queues[0].erase(--it.base());
			return true;
		}

		return false;
	}

	void abort_all(target_type target) {
		auto it = std::remove_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end())
			_queues[0].erase(it, _queues[0].end());
	}

	/// Dispatches events with timeout
	/// @return Number of invoked handlers
	size_t dispatch(clock_type::duration timeout) {
		size_t count = 0;

		std::swap(_queues[0], _queues[1]);

		auto start = clock_type::now();

		while (!_queues[1].empty()) {
			auto&& p = _queues[1].front();
			count += invoke(p.first, p.second);
			_queues[1].pop_front();

			if (clock_type::now() - start >= timeout)
				break;
		}

		// Insert not processed events to the main queue
		if (!_queues[1].empty()) {
			_queues[0].insert(_queues[0].begin(),
				std::make_move_iterator(_queues[1].begin()),
				std::make_move_iterator(_queues[1].end()));

			_queues[1].clear();
		}

		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(event->target());
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(target_type target, const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

private:
	typedef std::unordered_multimap<target_type, handler_type, dont_hash<target_type>> Handlers;
	Handlers _handlers;

	typedef std::deque<std::pair<target_type, ref_ptr<event>>> Events;
	std::array<Events, 2> _queues;
};

/// Helper base class for objects to subscribe to and automatically unsubscribe from events
template <typename T>
class event_subscriber {
public:
	explicit event_subscriber(event_dispatcher& dispatcher)
		: _dispatcher(dispatcher)
	{
	}

	~event_subscriber() {
		for (auto&& s : _subscriptions) {
			BOOST_VERIFY(_dispatcher.unsubscribe(s.first, s.second));
		}
	}

	template <typename E>
	void subscribe(void(T::*mf)(E*)) {
		auto handler_hash = _dispatcher.subscribe(mf, static_cast<T*>(this));
		_subscriptions.emplace_back(E::type, handler_hash);
	}

	template <typename E>
	bool subscribed(void(T::*mf)(E*)) const {
		return _dispatcher.subscribed(mf, static_cast<T*>(this));
	}

	template <typename E>
	void unsubscribe(void(T::*mf)(E*)) {
		size_t handler_hash = 0;
		BOOST_VERIFY(_dispatcher.unsubscribe(mf, static_cast<T*>(this), &handler_hash));
		// Remove handler hash for event type from subscriptions
		auto it = std::find(_subscriptions.begin(), _subscriptions.end(), std::make_pair(E::type, handler_hash));
		if (it != _subscriptions.end())
			_subscriptions.erase(it);
	}

private:
	event_dispatcher& _dispatcher;

	typedef std::deque<std::pair<event_dispatcher::target_type, size_t>> Subscriptions;
	Subscriptions _subscriptions;
};

/// Base class for objects to make them event targets
template
<
	typename T,
	subscribe_mode Mode = subscribe_mode::type_and_name
>
class event_target {
public:
	explicit event_target(event_dispatcher& dispatcher, const char* target_name = nullptr)
		: _dispatcher(dispatcher)
		, _target(get_target(target_name))
	{
		using std::placeholders::_1;

		event_dispatcher::handler_type handler = std::bind(&event_target::on_event, static_cast<T*>(this), _1);
		_handler_hash = _dispatcher.subscribe(_target, handler);
	}

	virtual ~event_target() {
		BOOST_VERIFY(_dispatcher.unsubscribe(_target, _handler_hash));
	}

	virtual void on_event(event*) = 0;

	static event_dispatcher::target_type get_target(const char* target_name) {
		static_assert(std::is_same<event_dispatcher::target_type, hash_type>::value, "target_type is not hash_type");

		hash_type hash_value = 0;

		if ((Mode & subscribe_mode::type) == subscribe_mode::type)
			hash_value = typeid(T).hash_code();

		if ((Mode & subscribe_mode::name) == subscribe_mode::name && target_name != nullptr)
				hash_value = murmur3(target_name, std::strlen(target_name), hash_value);

		return hash_value;
	}

private:
	event_dispatcher& _dispatcher;
	event_dispatcher::target_type _target = 0;
	size_t _handler_hash = 0;
};

} // namespace cobalt

#endif // COBALT_EVENTS_HPP_INCLUDED
<commit_msg>Added assertion<commit_after>#ifndef COBALT_EVENTS_HPP_INCLUDED
#define COBALT_EVENTS_HPP_INCLUDED

#pragma once

// Classes in this file:
//     event
//     basic_event
//     rebind_event_handler
//     event_dispatcher
//     event_subscriber
//     event_target

#include <cobalt/utility/intrusive.hpp>
#include <cobalt/utility/hash.hpp>
#include <cobalt/utility/enum_traits.hpp>

#include <boost/assert.hpp>

#include <array>
#include <deque>
#include <unordered_map>
#include <chrono>

CO_DEFINE_ENUM_CLASS(
	event_phase, uint8_t,
	bubbling,
	capture,
	sinking
)

CO_DEFINE_ENUM_FLAGS_CLASS(
	subscribe_mode, uint8_t,
	type = 1 << 0,
	name = 1 << 1,
	type_and_name = type | name
)

namespace cobalt {

/// event
class event : public ref_counter<event> {
public:
	typedef hash_type target_type;

	virtual ~event() = default;
	virtual target_type target() const = 0;
};

/// basic_event
template <event::target_type Target>
class basic_event : public event {
public:
	static constexpr target_type type = Target;

	virtual target_type target() const override { return Target; }
};

#define CO_DEFINE_EVENT_CLASS(event_class_name) class event_class_name : public basic_event<#event_class_name##_hash>

/// rebind_event_handler
template
<
	typename T,
	typename E,
	typename = typename std::enable_if<std::is_base_of<event, E>::value>::type
>
class rebind_event_handler {
public:
	rebind_event_handler(void(T::*mf)(E*), T* obj)
		: _obj(obj)
		, _mf(mf)
	{
	}

	void operator()(event* ev) {
		(_obj->*_mf)(static_cast<E*>(ev));
	}

	friend bool operator==(const rebind_event_handler& rhs, const rebind_event_handler& lhs) {
		return rhs._obj == lhs._obj && rhs._mf == lhs._mf;
	}

private:
	T* _obj;
	void(T::*_mf)(E*);
};

/// event_dispatcher
class event_dispatcher {
public:
	typedef event::target_type target_type;
	typedef std::function<void(event*)> handler_type;
	typedef std::chrono::high_resolution_clock clock_type;

	event_dispatcher() = default;

	// subscribe/subscribed/unsubscribe

	size_t subscribe(target_type target, handler_type handler) {
		size_t handler_hash = handler.target_type().hash_code();
		_handlers.emplace(target, std::move(handler));
		return handler_hash;
	}

	bool subscribed(target_type target, handler_type handler) const {
		return subscribed(target, handler.target_type().hash_code());
	}

	bool subscribed(target_type target, size_t handler_hash) const {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash)
				return true;
		}
		return false;
	}

	bool unsubscribe(target_type target, handler_type handler) {
		return unsubscribe(target, handler.target_type().hash_code());
	}

	bool unsubscribe(target_type target, size_t handler_hash) {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash) {
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// subscribe/subscribed/unsubscribe templated overloads for member functions

	template <typename T, typename E>
	size_t subscribe(void(T::*mf)(E*), T* obj) {
		subscribe(E::type, rebind_event_handler<T, E>(mf, obj));
		return typeid(rebind_event_handler<T, E>).hash_code();
	}

	template <typename T, typename E>
	bool subscribed(void(T::*mf)(E*), T* obj) const {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj))
				return true;
		}
		return false;
	}

	template <typename T, typename E>
	bool unsubscribe(void(T::*mf)(E*), T* obj, size_t* handler_hash = nullptr) {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj)) {
				if (handler_hash)
					*handler_hash = (*it).second.target_type().hash_code();
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// post/dispatch/invoke

	bool empty() const {
		return _queues[0].empty();
	}

	void post(const ref_ptr<event>& event) {
		_queues[0].emplace_back(event->target(), event);
	}

	void post(ref_ptr<event>&& event) {
		_queues[0].emplace_back(event->target(), std::move(event));
	}

	void post(target_type target, const ref_ptr<event>& event) {
		_queues[0].emplace_back(target, event);
	}

	void post(target_type target, ref_ptr<event>&& event) {
		_queues[0].emplace_back(target, std::move(event));
	}

	bool posted(target_type target) const {
		for (auto&& p : _queues[0]) {
			if (p.first == target)
				return true;
		}
		return false;
	}

	bool abort_first(target_type target) {
		auto it = std::find_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end()) {
			_queues[0].erase(it);
			return true;
		}

		return false;
	}

	bool abort_last(target_type target) {
		auto it = std::find_if(_queues[0].rbegin(), _queues[0].rend(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].rend()) {
			_queues[0].erase(--it.base());
			return true;
		}

		return false;
	}

	void abort_all(target_type target) {
		auto it = std::remove_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end())
			_queues[0].erase(it, _queues[0].end());
	}

	/// Dispatches events with timeout
	/// @return Number of invoked handlers
	size_t dispatch(clock_type::duration timeout) {
		size_t count = 0;

		std::swap(_queues[0], _queues[1]);

		auto start = clock_type::now();

		while (!_queues[1].empty()) {
			auto&& p = _queues[1].front();
			count += invoke(p.first, p.second);
			_queues[1].pop_front();

			if (clock_type::now() - start >= timeout)
				break;
		}

		// Insert not processed events to the main queue
		if (!_queues[1].empty()) {
			_queues[0].insert(_queues[0].begin(),
				std::make_move_iterator(_queues[1].begin()),
				std::make_move_iterator(_queues[1].end()));

			_queues[1].clear();
		}

		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(event->target());
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(target_type target, const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

private:
	typedef std::unordered_multimap<target_type, handler_type, dont_hash<target_type>> Handlers;
	Handlers _handlers;

	typedef std::deque<std::pair<target_type, ref_ptr<event>>> Events;
	std::array<Events, 2> _queues;
};

/// Helper base class for objects to subscribe to and automatically unsubscribe from events
template <typename T>
class event_subscriber {
public:
	explicit event_subscriber(event_dispatcher& dispatcher)
		: _dispatcher(dispatcher)
	{
	}

	~event_subscriber() {
		for (auto&& s : _subscriptions) {
			BOOST_VERIFY(_dispatcher.unsubscribe(s.first, s.second));
		}
	}

	template <typename E>
	void subscribe(void(T::*mf)(E*)) {
		auto handler_hash = _dispatcher.subscribe(mf, static_cast<T*>(this));
		_subscriptions.emplace_back(E::type, handler_hash);
	}

	template <typename E>
	bool subscribed(void(T::*mf)(E*)) const {
		return _dispatcher.subscribed(mf, static_cast<T*>(this));
	}

	template <typename E>
	void unsubscribe(void(T::*mf)(E*)) {
		size_t handler_hash = 0;
		BOOST_VERIFY(_dispatcher.unsubscribe(mf, static_cast<T*>(this), &handler_hash));
		// Remove handler hash for event type from subscriptions
		auto it = std::find(_subscriptions.begin(), _subscriptions.end(), std::make_pair(E::type, handler_hash));
		if (it != _subscriptions.end())
			_subscriptions.erase(it);
	}

private:
	event_dispatcher& _dispatcher;

	typedef std::deque<std::pair<event_dispatcher::target_type, size_t>> Subscriptions;
	Subscriptions _subscriptions;
};

/// Base class for objects to make them event targets
template
<
	typename T,
	subscribe_mode Mode = subscribe_mode::type_and_name
>
class event_target {
public:
	explicit event_target(event_dispatcher& dispatcher, const char* target_name = nullptr)
		: _dispatcher(dispatcher)
		, _target(get_target(target_name))
	{
		using std::placeholders::_1;

		event_dispatcher::handler_type handler = std::bind(&event_target::on_event, static_cast<T*>(this), _1);
		_handler_hash = _dispatcher.subscribe(_target, handler);
	}

	virtual ~event_target() {
		BOOST_VERIFY(_dispatcher.unsubscribe(_target, _handler_hash));
	}

	virtual void on_event(event*) = 0;

	static event_dispatcher::target_type get_target(const char* target_name) {
		static_assert(std::is_same<event_dispatcher::target_type, hash_type>::value, "target_type is not hash_type");

		hash_type hash_value = 0;

		if ((Mode & subscribe_mode::type) == subscribe_mode::type)
			hash_value = typeid(T).hash_code();

		if ((Mode & subscribe_mode::name) == subscribe_mode::name && target_name != nullptr)
			hash_value = murmur3(target_name, std::strlen(target_name), hash_value);

		BOOST_ASSERT_MSG(hash_value != 0, "Cannot identify target");

		return hash_value;
	}

private:
	event_dispatcher& _dispatcher;
	event_dispatcher::target_type _target = 0;
	size_t _handler_hash = 0;
};

} // namespace cobalt

#endif // COBALT_EVENTS_HPP_INCLUDED
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/labs.h"

#include <algorithm>
#include <iterator>
#include <map>
#include <set>

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/values.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"

namespace about_labs {

enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };

unsigned kOsAll = kOsMac | kOsWin | kOsLinux;

struct Experiment {
  // The internal name of the experiment. This is never shown to the user.
  // It _is_ however stored in the prefs file, so you shouldn't change the
  // name of existing labs.
  const char* internal_name;

  // String id of the message containing the experiment's name.
  int visible_name_id;

  // String id of the message containing the experiment's description.
  int visible_description_id;

  // The platforms the experiment is available on
  // Needs to be more than a compile-time #ifdef because of profile sync.
  unsigned supported_platforms;  // bitmask

  // The commandline parameter that's added when this lab is active. This is
  // different from |internal_name| so that the commandline flag can be
  // renamed without breaking the prefs file.
  const char* command_line;
};

const Experiment kExperiments[] = {
  {
    "expose-for-tabs",  // Do not change; see above.
    IDS_LABS_TABPOSE_NAME,
    IDS_LABS_TABPOSE_DESCRIPTION,
    kOsMac,
#if defined(OS_MACOSX)
    // The switch exists only on OS X.
    switches::kEnableExposeForTabs
#else
    ""
#endif
  },
  {
    "vertical-tabs",  // Do not change; see above.
    IDS_LABS_SIDE_TABS_NAME,
    IDS_LABS_SIDE_TABS_DESCRIPTION,
    kOsWin,
    switches::kEnableVerticalTabs
  },
  {
    "tabbed-options",  // Do not change; see above.
    IDS_LABS_TABBED_OPTIONS_NAME,
    IDS_LABS_TABBED_OPTIONS_DESCRIPTION,
    kOsAll,
    switches::kEnableTabbedOptions
  },
  {
    "match-preview",  // Do not change; see above.
    IDS_LABS_INSTANT_NAME,
    IDS_LABS_INSTANT_DESCRIPTION,
    kOsWin,
    switches::kEnableMatchPreview
  },
  {
    "remoting",  // Do not change; see above.
    IDS_LABS_REMOTING_NAME,
#if defined(OS_WINDOWS)
    // Windows only supports host functionality at the moment.
    IDS_LABS_REMOTING_HOST_DESCRIPTION,
#elif defined(OS_LINUX)
    // Linux only supports client functionality at the moment.
    IDS_LABS_REMOTING_CLIENT_DESCRIPTION,
#else
    // On other platforms, this lab isn't available at all.
    0,
#endif
    kOsWin | kOsLinux,
    switches::kEnableRemoting
  },
};

// Extracts the list of enabled lab experiments from a profile and stores them
// in a set.
void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
  const ListValue* enabled_experiments = prefs->GetList(
      prefs::kEnabledLabsExperiments);
  if (!enabled_experiments)
    return;

  for (ListValue::const_iterator it = enabled_experiments->begin();
       it != enabled_experiments->end();
       ++it) {
    std::string experiment_name;
    if (!(*it)->GetAsString(&experiment_name)) {
      LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
      continue;
    }
    result->insert(experiment_name);
  }
}

// Takes a set of enabled lab experiments
void SetEnabledLabs(
    PrefService* prefs, const std::set<std::string>& enabled_experiments) {
  ListValue* experiments_list = prefs->GetMutableList(
      prefs::kEnabledLabsExperiments);
  if (!experiments_list)
    return;

  experiments_list->Clear();
  for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
       it != enabled_experiments.end();
       ++it) {
    experiments_list->Append(new StringValue(*it));
  }
}

// Removes all experiments from prefs::kEnabledLabsExperiments that are
// unknown, to prevent this list to become very long as experiments are added
// and removed.
void SanitizeList(PrefService* prefs) {
  std::set<std::string> known_experiments;
  for (size_t i = 0; i < arraysize(kExperiments); ++i)
    known_experiments.insert(kExperiments[i].internal_name);

  std::set<std::string> enabled_experiments;
  GetEnabledLabs(prefs, &enabled_experiments);

  std::set<std::string> new_enabled_experiments;
  std::set_intersection(
      known_experiments.begin(), known_experiments.end(),
      enabled_experiments.begin(), enabled_experiments.end(),
      std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));

  SetEnabledLabs(prefs, new_enabled_experiments);
}

void GetSanitizedEnabledLabs(
    PrefService* prefs, std::set<std::string>* result) {
  SanitizeList(prefs);
  GetEnabledLabs(prefs, result);
}

int GetCurrentPlatform() {
#if defined(OS_MACOSX)
  return kOsMac;
#elif defined(OS_WIN)
  return kOsWin;
#elif defined(OS_LINUX)
  return kOsLinux;
#else
#error Unknown platform
#endif
}

bool IsEnabled() {
#if defined(OS_CHROMEOS)
  // ChromeOS uses a different mechanism for about:labs; integrated with their
  // dom ui options.
  return false;
#elif defined(GOOGLE_CHROME_BUILD)
  // Don't enable this on the stable channel.
  return !platform_util::GetVersionStringModifier().empty();
#else
  return true;
#endif
}

void ConvertLabsToSwitches(Profile* profile, CommandLine* command_line) {
  // Do not activate labs features on the stable channel.
  if (!IsEnabled())
    return;

  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  std::map<std::string, const Experiment*> experiments;
  for (size_t i = 0; i < arraysize(kExperiments); ++i)
    experiments[kExperiments[i].internal_name] = &kExperiments[i];

  for (std::set<std::string>::iterator it = enabled_experiments.begin();
       it != enabled_experiments.end();
       ++it) {
    const std::string& experiment_name = *it;
    std::map<std::string, const Experiment*>::iterator experiment =
        experiments.find(experiment_name);
    DCHECK(experiment != experiments.end());
    if (experiment == experiments.end())
      continue;

    command_line->AppendSwitch(experiment->second->command_line);
  }
}

ListValue* GetLabsExperimentsData(Profile* profile) {
  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  int current_platform = GetCurrentPlatform();

  ListValue* experiments_data = new ListValue();
  for (size_t i = 0; i < arraysize(kExperiments); ++i) {
    const Experiment& experiment = kExperiments[i];
    if (!(experiment.supported_platforms & current_platform))
      continue;

    DictionaryValue* data = new DictionaryValue();
    data->SetString("internal_name", experiment.internal_name);
    data->SetString("name",
                    l10n_util::GetStringUTF16(experiment.visible_name_id));
    data->SetString("description",
                    l10n_util::GetStringUTF16(
                        experiment.visible_description_id));
    data->SetBoolean("enabled",
                      enabled_experiments.count(experiment.internal_name) > 0);

    experiments_data->Append(data);
  }
  return experiments_data;
}

static bool needs_restart_ = false;

bool IsRestartNeededToCommitChanges() {
  return needs_restart_;
}

void SetExperimentEnabled(
    Profile* profile, const std::string& internal_name, bool enable) {
  needs_restart_ = true;

  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  if (enable)
    enabled_experiments.insert(internal_name);
  else
    enabled_experiments.erase(internal_name);

  SetEnabledLabs(profile->GetPrefs(), enabled_experiments);
}

}  // namespace Labs
<commit_msg>Fix a typo introduced in r60578.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/labs.h"

#include <algorithm>
#include <iterator>
#include <map>
#include <set>

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/values.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"

namespace about_labs {

enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };

unsigned kOsAll = kOsMac | kOsWin | kOsLinux;

struct Experiment {
  // The internal name of the experiment. This is never shown to the user.
  // It _is_ however stored in the prefs file, so you shouldn't change the
  // name of existing labs.
  const char* internal_name;

  // String id of the message containing the experiment's name.
  int visible_name_id;

  // String id of the message containing the experiment's description.
  int visible_description_id;

  // The platforms the experiment is available on
  // Needs to be more than a compile-time #ifdef because of profile sync.
  unsigned supported_platforms;  // bitmask

  // The commandline parameter that's added when this lab is active. This is
  // different from |internal_name| so that the commandline flag can be
  // renamed without breaking the prefs file.
  const char* command_line;
};

const Experiment kExperiments[] = {
  {
    "expose-for-tabs",  // Do not change; see above.
    IDS_LABS_TABPOSE_NAME,
    IDS_LABS_TABPOSE_DESCRIPTION,
    kOsMac,
#if defined(OS_MACOSX)
    // The switch exists only on OS X.
    switches::kEnableExposeForTabs
#else
    ""
#endif
  },
  {
    "vertical-tabs",  // Do not change; see above.
    IDS_LABS_SIDE_TABS_NAME,
    IDS_LABS_SIDE_TABS_DESCRIPTION,
    kOsWin,
    switches::kEnableVerticalTabs
  },
  {
    "tabbed-options",  // Do not change; see above.
    IDS_LABS_TABBED_OPTIONS_NAME,
    IDS_LABS_TABBED_OPTIONS_DESCRIPTION,
    kOsAll,
    switches::kEnableTabbedOptions
  },
  {
    "match-preview",  // Do not change; see above.
    IDS_LABS_INSTANT_NAME,
    IDS_LABS_INSTANT_DESCRIPTION,
    kOsWin,
    switches::kEnableMatchPreview
  },
  {
    "remoting",  // Do not change; see above.
    IDS_LABS_REMOTING_NAME,
#if defined(OS_WIN)
    // Windows only supports host functionality at the moment.
    IDS_LABS_REMOTING_HOST_DESCRIPTION,
#elif defined(OS_LINUX)
    // Linux only supports client functionality at the moment.
    IDS_LABS_REMOTING_CLIENT_DESCRIPTION,
#else
    // On other platforms, this lab isn't available at all.
    0,
#endif
    kOsWin | kOsLinux,
    switches::kEnableRemoting
  },
};

// Extracts the list of enabled lab experiments from a profile and stores them
// in a set.
void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
  const ListValue* enabled_experiments = prefs->GetList(
      prefs::kEnabledLabsExperiments);
  if (!enabled_experiments)
    return;

  for (ListValue::const_iterator it = enabled_experiments->begin();
       it != enabled_experiments->end();
       ++it) {
    std::string experiment_name;
    if (!(*it)->GetAsString(&experiment_name)) {
      LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
      continue;
    }
    result->insert(experiment_name);
  }
}

// Takes a set of enabled lab experiments
void SetEnabledLabs(
    PrefService* prefs, const std::set<std::string>& enabled_experiments) {
  ListValue* experiments_list = prefs->GetMutableList(
      prefs::kEnabledLabsExperiments);
  if (!experiments_list)
    return;

  experiments_list->Clear();
  for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
       it != enabled_experiments.end();
       ++it) {
    experiments_list->Append(new StringValue(*it));
  }
}

// Removes all experiments from prefs::kEnabledLabsExperiments that are
// unknown, to prevent this list to become very long as experiments are added
// and removed.
void SanitizeList(PrefService* prefs) {
  std::set<std::string> known_experiments;
  for (size_t i = 0; i < arraysize(kExperiments); ++i)
    known_experiments.insert(kExperiments[i].internal_name);

  std::set<std::string> enabled_experiments;
  GetEnabledLabs(prefs, &enabled_experiments);

  std::set<std::string> new_enabled_experiments;
  std::set_intersection(
      known_experiments.begin(), known_experiments.end(),
      enabled_experiments.begin(), enabled_experiments.end(),
      std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));

  SetEnabledLabs(prefs, new_enabled_experiments);
}

void GetSanitizedEnabledLabs(
    PrefService* prefs, std::set<std::string>* result) {
  SanitizeList(prefs);
  GetEnabledLabs(prefs, result);
}

int GetCurrentPlatform() {
#if defined(OS_MACOSX)
  return kOsMac;
#elif defined(OS_WIN)
  return kOsWin;
#elif defined(OS_LINUX)
  return kOsLinux;
#else
#error Unknown platform
#endif
}

bool IsEnabled() {
#if defined(OS_CHROMEOS)
  // ChromeOS uses a different mechanism for about:labs; integrated with their
  // dom ui options.
  return false;
#elif defined(GOOGLE_CHROME_BUILD)
  // Don't enable this on the stable channel.
  return !platform_util::GetVersionStringModifier().empty();
#else
  return true;
#endif
}

void ConvertLabsToSwitches(Profile* profile, CommandLine* command_line) {
  // Do not activate labs features on the stable channel.
  if (!IsEnabled())
    return;

  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  std::map<std::string, const Experiment*> experiments;
  for (size_t i = 0; i < arraysize(kExperiments); ++i)
    experiments[kExperiments[i].internal_name] = &kExperiments[i];

  for (std::set<std::string>::iterator it = enabled_experiments.begin();
       it != enabled_experiments.end();
       ++it) {
    const std::string& experiment_name = *it;
    std::map<std::string, const Experiment*>::iterator experiment =
        experiments.find(experiment_name);
    DCHECK(experiment != experiments.end());
    if (experiment == experiments.end())
      continue;

    command_line->AppendSwitch(experiment->second->command_line);
  }
}

ListValue* GetLabsExperimentsData(Profile* profile) {
  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  int current_platform = GetCurrentPlatform();

  ListValue* experiments_data = new ListValue();
  for (size_t i = 0; i < arraysize(kExperiments); ++i) {
    const Experiment& experiment = kExperiments[i];
    if (!(experiment.supported_platforms & current_platform))
      continue;

    DictionaryValue* data = new DictionaryValue();
    data->SetString("internal_name", experiment.internal_name);
    data->SetString("name",
                    l10n_util::GetStringUTF16(experiment.visible_name_id));
    data->SetString("description",
                    l10n_util::GetStringUTF16(
                        experiment.visible_description_id));
    data->SetBoolean("enabled",
                      enabled_experiments.count(experiment.internal_name) > 0);

    experiments_data->Append(data);
  }
  return experiments_data;
}

static bool needs_restart_ = false;

bool IsRestartNeededToCommitChanges() {
  return needs_restart_;
}

void SetExperimentEnabled(
    Profile* profile, const std::string& internal_name, bool enable) {
  needs_restart_ = true;

  std::set<std::string> enabled_experiments;
  GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);

  if (enable)
    enabled_experiments.insert(internal_name);
  else
    enabled_experiments.erase(internal_name);

  SetEnabledLabs(profile->GetPrefs(), enabled_experiments);
}

}  // namespace Labs
<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "mfem.hpp"
#include "unit_tests.hpp"
#include "linalg/dtensor.hpp"

using namespace mfem;

TEST_CASE("DenseMatrix init-list construction", "[DenseMatrix]")
{
   double ContigData[6] = {6.0, 5.0, 4.0, 3.0, 2.0, 1.0};
   DenseMatrix Contiguous(ContigData, 2, 3);

   DenseMatrix Nested(
   {
      {6.0, 4.0, 2.0},
      {5.0, 3.0, 1.0}
   });

   for (int i = 0; i < Contiguous.Height(); i++)
   {
      for (int j = 0; j < Contiguous.Width(); j++)
      {
         REQUIRE(Nested(i,j) == Contiguous(i,j));
      }
   }
}

TEST_CASE("DenseMatrix LinearSolve methods",
          "[DenseMatrix]")
{
   SECTION("singular_system")
   {
      constexpr int N = 3;

      DenseMatrix A(N);
      A.SetRow(0, 0.0);
      A.SetRow(1, 0.0);
      A.SetRow(2, 0.0);

      double X[3];

      REQUIRE_FALSE(LinearSolve(A,X));
   }

   SECTION("1x1_system")
   {
      constexpr int N = 1;
      DenseMatrix A(N);
      A(0,0) = 2;

      double X[1] = { 12 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(6));
   }

   SECTION("2x2_system")
   {
      constexpr int N = 2;

      DenseMatrix A(N);
      A(0,0) = 2.0; A(0,1) = 1.0;
      A(1,0) = 3.0; A(1,1) = 4.0;

      double X[2] = { 1, 14 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(-2));
      REQUIRE(X[1] == MFEM_Approx(5));
   }

   SECTION("3x3_system")
   {
      constexpr int N = 3;

      DenseMatrix A(N);
      A(0,0) = 4; A(0,1) =  5; A(0,2) = -2;
      A(1,0) = 7; A(1,1) = -1; A(1,2) =  2;
      A(2,0) = 3; A(2,1) =  1; A(2,2) =  4;

      double X[3] = { -14, 42, 28 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(4));
      REQUIRE(X[1] == MFEM_Approx(-4));
      REQUIRE(X[2] == MFEM_Approx(5));
   }

}

TEST_CASE("DenseMatrix A*B^T methods",
          "[DenseMatrix]")
{
   double tol = 1e-12;

   double AtData[6] = {6.0, 5.0,
                       4.0, 3.0,
                       2.0, 1.0
                      };
   double BtData[12] = {1.0, 3.0, 5.0, 7.0,
                        2.0, 4.0, 6.0, 8.0,
                        1.0, 2.0, 3.0, 5.0
                       };

   DenseMatrix A(AtData, 2, 3);
   DenseMatrix B(BtData, 4, 3);
   DenseMatrix C(2,4);

   SECTION("MultABt")
   {
      double BData[12] = {1.0, 2.0, 1.0,
                          3.0, 4.0, 2.0,
                          5.0, 6.0, 3.0,
                          7.0, 8.0, 5.0
                         };
      DenseMatrix Bt(BData, 3, 4);

      double CtData[8] = {16.0, 12.0,
                          38.0, 29.0,
                          60.0, 46.0,
                          84.0, 64.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      MultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      Mult(A, Bt, Cexact);
      MultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("MultADBt")
   {
      double DData[3] = {11.0, 7.0, 5.0};
      Vector D(DData, 3);

      double CtData[8] = {132.0, 102.0,
                          330.0, 259.0,
                          528.0, 416.0,
                          736.0, 578.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      MultADBt(A, D, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMultABt")
   {
      double CtData[8] = {17.0, 17.0,
                          40.0, 35.0,
                          63.0, 53.0,
                          88.0, 72.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultABt(A, B, C);
      C *= -1.0;
      AddMultABt(A, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMultADBt")
   {
      double DData[3] = {11.0, 7.0, 5.0};
      Vector D(DData, 3);

      double CtData[8] = {133.0, 107.0,
                          332.0, 265.0,
                          531.0, 423.0,
                          740.0, 586.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMultADBt(A, D, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultADBt(A, D, B, C);
      C *= -1.0;
      AddMultADBt(A, D, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);

      DData[0] = 1.0; DData[1] = 1.0; DData[2] = 1.0;
      MultABt(A, B, C);
      C *= -1.0;
      AddMultADBt(A, D, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMult_a_ABt")
   {
      double a = 3.0;

      double CtData[8] = { 49.0,  41.0,
                           116.0,  93.0,
                           183.0, 145.0,
                           256.0, 200.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMult_a_ABt(a, A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultABt(A, B, C);
      AddMult_a_ABt(-1.0, A, B, C);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
}

TEST_CASE("LUFactors RightSolve", "[DenseMatrix]")
{
   double tol = 1e-12;

   // Zero on diagonal forces non-trivial pivot
   double AData[9] = { 0.0, 0.0, 3.0, 2.0, 2.0, 2.0, 2.0, 0.0, 4.0 };
   double BData[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
   int ipiv[3];

   DenseMatrix A(AData, 3, 3);
   DenseMatrix B(BData, 2, 3);

   DenseMatrixInverse Af1(A);
   DenseMatrix Ainv;
   Af1.GetInverseMatrix(Ainv);

   LUFactors Af2(AData, ipiv);
   Af2.Factor(3);

   DenseMatrix C(2,3);
   Mult(B, Ainv, C);
   Af2.RightSolve(3, 2, B.GetData());
   C -= B;

   REQUIRE(C.MaxMaxNorm() < tol);
}

TEST_CASE("DenseTensor LinearSolve methods",
          "[DenseMatrix]")
{

   int N = 3;
   DenseMatrix A(N);
   A(0,0) = 4; A(0,1) =  5; A(0,2) = -2;
   A(1,0) = 7; A(1,1) = -1; A(1,2) =  2;
   A(2,0) = 3; A(2,1) =  1; A(2,2) =  4;

   double X[3] = { -14, 42, 28 };

   int NE = 10;
   Vector X_batch(N*NE);
   DenseTensor A_batch(N,N,NE);

   auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE);
   auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE);
   // Column major
   for (int e=0; e<NE; ++e)
   {

      for (int r=0; r<N; ++r)
      {
         for (int c=0; c<N; ++c)
         {
            a_batch(c, r, e) = A.GetData()[c+r*N];
         }
         x_batch(r,e) = X[r];
      }
   }

   Array<int> P;
   BatchLUFactor(A_batch, P);
   BatchLUSolve(A_batch, P, X_batch);

   auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE);
   REQUIRE(LinearSolve(A,X));
   for (int e=0; e<NE; ++e)
   {
      for (int r=0; r<N; ++r)
      {
         REQUIRE(xans_batch(r,e) == MFEM_Approx(X[r]));
      }
   }
}

TEST_CASE("DenseTensor copy", "[DenseMatrix][DenseTensor]")
{
   DenseTensor t1(2,3,4);
   for (int i=0; i<t1.TotalSize(); ++i)
   {
      t1.Data()[i] = i;
   }
   DenseTensor t2(t1);
   DenseTensor t3;
   t3 = t1;
   REQUIRE(t2.SizeI() == t1.SizeI());
   REQUIRE(t2.SizeJ() == t1.SizeJ());
   REQUIRE(t2.SizeK() == t1.SizeK());

   REQUIRE(t3.SizeI() == t1.SizeI());
   REQUIRE(t3.SizeJ() == t1.SizeJ());
   REQUIRE(t3.SizeK() == t1.SizeK());

   REQUIRE(t2.Data() != t1.Data());
   REQUIRE(t3.Data() != t1.Data());

   for (int i=0; i<t1.TotalSize(); ++i)
   {
      REQUIRE(t2.Data()[i] == t1.Data()[i]);
      REQUIRE(t3.Data()[i] == t1.Data()[i]);
   }
}
<commit_msg>adding unit tests for Generalized EigSystem and SVDs<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "mfem.hpp"
#include "unit_tests.hpp"
#include "linalg/dtensor.hpp"

using namespace mfem;

TEST_CASE("DenseMatrix init-list construction", "[DenseMatrix]")
{
   double ContigData[6] = {6.0, 5.0, 4.0, 3.0, 2.0, 1.0};
   DenseMatrix Contiguous(ContigData, 2, 3);

   DenseMatrix Nested(
   {
      {6.0, 4.0, 2.0},
      {5.0, 3.0, 1.0}
   });

   for (int i = 0; i < Contiguous.Height(); i++)
   {
      for (int j = 0; j < Contiguous.Width(); j++)
      {
         REQUIRE(Nested(i,j) == Contiguous(i,j));
      }
   }
}

TEST_CASE("DenseMatrix LinearSolve methods",
          "[DenseMatrix]")
{
   SECTION("singular_system")
   {
      constexpr int N = 3;

      DenseMatrix A(N);
      A.SetRow(0, 0.0);
      A.SetRow(1, 0.0);
      A.SetRow(2, 0.0);

      double X[3];

      REQUIRE_FALSE(LinearSolve(A,X));
   }

   SECTION("1x1_system")
   {
      constexpr int N = 1;
      DenseMatrix A(N);
      A(0,0) = 2;

      double X[1] = { 12 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(6));
   }

   SECTION("2x2_system")
   {
      constexpr int N = 2;

      DenseMatrix A(N);
      A(0,0) = 2.0; A(0,1) = 1.0;
      A(1,0) = 3.0; A(1,1) = 4.0;

      double X[2] = { 1, 14 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(-2));
      REQUIRE(X[1] == MFEM_Approx(5));
   }

   SECTION("3x3_system")
   {
      constexpr int N = 3;

      DenseMatrix A(N);
      A(0,0) = 4; A(0,1) =  5; A(0,2) = -2;
      A(1,0) = 7; A(1,1) = -1; A(1,2) =  2;
      A(2,0) = 3; A(2,1) =  1; A(2,2) =  4;

      double X[3] = { -14, 42, 28 };

      REQUIRE(LinearSolve(A,X));
      REQUIRE(X[0] == MFEM_Approx(4));
      REQUIRE(X[1] == MFEM_Approx(-4));
      REQUIRE(X[2] == MFEM_Approx(5));
   }

}

TEST_CASE("DenseMatrix A*B^T methods",
          "[DenseMatrix]")
{
   double tol = 1e-12;

   double AtData[6] = {6.0, 5.0,
                       4.0, 3.0,
                       2.0, 1.0
                      };
   double BtData[12] = {1.0, 3.0, 5.0, 7.0,
                        2.0, 4.0, 6.0, 8.0,
                        1.0, 2.0, 3.0, 5.0
                       };

   DenseMatrix A(AtData, 2, 3);
   DenseMatrix B(BtData, 4, 3);
   DenseMatrix C(2,4);

   SECTION("MultABt")
   {
      double BData[12] = {1.0, 2.0, 1.0,
                          3.0, 4.0, 2.0,
                          5.0, 6.0, 3.0,
                          7.0, 8.0, 5.0
                         };
      DenseMatrix Bt(BData, 3, 4);

      double CtData[8] = {16.0, 12.0,
                          38.0, 29.0,
                          60.0, 46.0,
                          84.0, 64.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      MultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      Mult(A, Bt, Cexact);
      MultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("MultADBt")
   {
      double DData[3] = {11.0, 7.0, 5.0};
      Vector D(DData, 3);

      double CtData[8] = {132.0, 102.0,
                          330.0, 259.0,
                          528.0, 416.0,
                          736.0, 578.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      MultADBt(A, D, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMultABt")
   {
      double CtData[8] = {17.0, 17.0,
                          40.0, 35.0,
                          63.0, 53.0,
                          88.0, 72.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMultABt(A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultABt(A, B, C);
      C *= -1.0;
      AddMultABt(A, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMultADBt")
   {
      double DData[3] = {11.0, 7.0, 5.0};
      Vector D(DData, 3);

      double CtData[8] = {133.0, 107.0,
                          332.0, 265.0,
                          531.0, 423.0,
                          740.0, 586.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMultADBt(A, D, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultADBt(A, D, B, C);
      C *= -1.0;
      AddMultADBt(A, D, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);

      DData[0] = 1.0; DData[1] = 1.0; DData[2] = 1.0;
      MultABt(A, B, C);
      C *= -1.0;
      AddMultADBt(A, D, B, C);
      REQUIRE(C.MaxMaxNorm() < tol);
   }
   SECTION("AddMult_a_ABt")
   {
      double a = 3.0;

      double CtData[8] = { 49.0,  41.0,
                           116.0,  93.0,
                           183.0, 145.0,
                           256.0, 200.0
                         };
      DenseMatrix Cexact(CtData, 2, 4);

      C(0, 0) = 1.0; C(0, 1) = 2.0; C(0, 2) = 3.0; C(0, 3) = 4.0;
      C(1, 0) = 5.0; C(1, 1) = 6.0; C(1, 2) = 7.0; C(1, 3) = 8.0;

      AddMult_a_ABt(a, A, B, C);
      C.Add(-1.0, Cexact);

      REQUIRE(C.MaxMaxNorm() < tol);

      MultABt(A, B, C);
      AddMult_a_ABt(-1.0, A, B, C);

      REQUIRE(C.MaxMaxNorm() < tol);
   }
}

TEST_CASE("LUFactors RightSolve", "[DenseMatrix]")
{
   double tol = 1e-12;

   // Zero on diagonal forces non-trivial pivot
   double AData[9] = { 0.0, 0.0, 3.0, 2.0, 2.0, 2.0, 2.0, 0.0, 4.0 };
   double BData[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
   int ipiv[3];

   DenseMatrix A(AData, 3, 3);
   DenseMatrix B(BData, 2, 3);

   DenseMatrixInverse Af1(A);
   DenseMatrix Ainv;
   Af1.GetInverseMatrix(Ainv);

   LUFactors Af2(AData, ipiv);
   Af2.Factor(3);

   DenseMatrix C(2,3);
   Mult(B, Ainv, C);
   Af2.RightSolve(3, 2, B.GetData());
   C -= B;

   REQUIRE(C.MaxMaxNorm() < tol);
}

TEST_CASE("DenseTensor LinearSolve methods",
          "[DenseMatrix]")
{

   int N = 3;
   DenseMatrix A(N);
   A(0,0) = 4; A(0,1) =  5; A(0,2) = -2;
   A(1,0) = 7; A(1,1) = -1; A(1,2) =  2;
   A(2,0) = 3; A(2,1) =  1; A(2,2) =  4;

   double X[3] = { -14, 42, 28 };

   int NE = 10;
   Vector X_batch(N*NE);
   DenseTensor A_batch(N,N,NE);

   auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE);
   auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE);
   // Column major
   for (int e=0; e<NE; ++e)
   {

      for (int r=0; r<N; ++r)
      {
         for (int c=0; c<N; ++c)
         {
            a_batch(c, r, e) = A.GetData()[c+r*N];
         }
         x_batch(r,e) = X[r];
      }
   }

   Array<int> P;
   BatchLUFactor(A_batch, P);
   BatchLUSolve(A_batch, P, X_batch);

   auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE);
   REQUIRE(LinearSolve(A,X));
   for (int e=0; e<NE; ++e)
   {
      for (int r=0; r<N; ++r)
      {
         REQUIRE(xans_batch(r,e) == MFEM_Approx(X[r]));
      }
   }
}

TEST_CASE("DenseTensor copy", "[DenseMatrix][DenseTensor]")
{
   DenseTensor t1(2,3,4);
   for (int i=0; i<t1.TotalSize(); ++i)
   {
      t1.Data()[i] = i;
   }
   DenseTensor t2(t1);
   DenseTensor t3;
   t3 = t1;
   REQUIRE(t2.SizeI() == t1.SizeI());
   REQUIRE(t2.SizeJ() == t1.SizeJ());
   REQUIRE(t2.SizeK() == t1.SizeK());

   REQUIRE(t3.SizeI() == t1.SizeI());
   REQUIRE(t3.SizeJ() == t1.SizeJ());
   REQUIRE(t3.SizeK() == t1.SizeK());

   REQUIRE(t2.Data() != t1.Data());
   REQUIRE(t3.Data() != t1.Data());

   for (int i=0; i<t1.TotalSize(); ++i)
   {
      REQUIRE(t2.Data()[i] == t1.Data()[i]);
      REQUIRE(t3.Data()[i] == t1.Data()[i]);
   }
}

#ifdef MFEM_USE_LAPACK

enum class TestCase { GenEigSPD, GenEigGE, SVD};
std::string TestCaseName(TestCase testcase)
{
   switch (testcase)
   {
      case TestCase::GenEigSPD:
         return "Generalized Eigenvalue problem for an SPD matrix";
      case TestCase::GenEigGE:
         return "Generalized Eigenvalue problem for a general matrix";
      case TestCase::SVD:
         return "Singula Value Decomposition for a general matrix";
   }
   return "";
}

TEST_CASE("Eigensystem Problems",
          "[DenseMatrix]")
{
   auto testcase = GENERATE(TestCase::GenEigSPD, TestCase::GenEigGE,
                            TestCase::SVD);

   CAPTURE(TestCaseName(testcase));

   DenseMatrix M({{0.279841, 0.844288, 0.498302, 0.323955},
      {0.884680, 0.243511, 0.397405, 0.265708},
      {0.649685, 0.700754, 0.586396, 0.023724},
      {0.081588, 0.728236, 0.083123, 0.488041}
   });

   switch (testcase)
   {
      case TestCase::GenEigSPD:
      {
         DenseMatrix A({{0.56806, 0.29211, 0.48315, 0.70024},
            {0.29211, 0.85147, 0.68123, 0.70689},
            {0.48315, 0.68123, 1.07229, 1.02681},
            {0.70024, 0.70689, 1.02681, 1.15468}});

         DenseMatrixGeneralizedEigensystem geig(A,M,true,true);
         geig.Eval();
         Vector & Lamda = geig.EigenvaluesRealPart();
         DenseMatrix & Vl = geig.LeftEigenvectors();
         DenseMatrix & Vr = geig.RightEigenvectors();

         // check A * Vr - L * M * Vr
         DenseMatrix AVr(4);
         DenseMatrix MVr(4);
         Mult(A,Vr,AVr);
         Mult(M,Vr,MVr);
         MVr.RightScaling(Lamda);
         AVr-=MVr;

         REQUIRE(AVr.MaxMaxNorm() == MFEM_Approx(0.));

         // check Vl^t * A - L * Vl^t * M
         DenseMatrix VltA(4);
         DenseMatrix VltM(4);
         MultAtB(Vl,A,VltA);
         MultAtB(Vl,M,VltM);
         VltM.LeftScaling(Lamda);
         VltA-=VltM;

         REQUIRE(VltA.MaxMaxNorm() == MFEM_Approx(0.));

      }
      break;
      case TestCase::GenEigGE:
      {
         DenseMatrix A({{0.486278, 0.041135, 0.480727, 0.616026},
            {0.523599, 0.119827, 0.087808, 0.415241},
            {0.214454, 0.661631, 0.909626, 0.744259},
            {0.107007, 0.630604, 0.077862, 0.221006}});

         mfem::out << "TestCase::GenEigGE: TODO" << std::endl;

      }
      break;
      case TestCase::SVD:
      {
         DenseMatrix Mc(M);
         DenseMatrixSVD svd(Mc,true,true);
         svd.Eval(Mc);
         Vector &sigma = svd.Singularvalues();
         DenseMatrix &U = svd.LeftSingularvectors();
         DenseMatrix &V = svd.RightSingularvectors();

         DenseMatrix Vt(V);
         Vt.Transpose();
         DenseMatrix USVt(4);
         MultADBt(U,sigma,Vt,USVt);

         USVt -= M;

         REQUIRE(USVt.MaxMaxNorm() == MFEM_Approx(0.));
      }
      break;
   }
}

#endif // if MFEM_USE_LAPACK<|endoftext|>


<commit_before>/*
* Copyright (C) 2015 German Aerospace Center (DLR/SC)
*
* Created: 2015-05-08 Martin Siggel <Martin.Siggel@dlr.de>
*
* 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 "tigl.h"
#include "tiglcommonfunctions.h"
#include "test.h"
#include <BRep_Builder.hxx>
#include <BRepTools.hxx>

#include <gp_Pln.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>

#include <list>

TEST(TiglCommonFunctions, isPathRelative)
{
    ASSERT_TRUE(IsPathRelative("./test.txt"));

    ASSERT_TRUE(IsPathRelative("test.txt"));

    ASSERT_TRUE(IsPathRelative("../test.txt"));

    // check absolute paths
#ifdef WIN32
    ASSERT_FALSE(IsPathRelative("d:/data/test.txt"));
#else
    ASSERT_FALSE(IsPathRelative("/usr/bin/test.txt"));
#endif
}

TEST(TiglCommonFunctions, isFileReadable)
{
    ASSERT_TRUE(IsFileReadable("TestData/nacelle.stp"));
    ASSERT_FALSE(IsFileReadable("invalidfile.txt"));
}

TEST(TiglCommonFunctions, getEdgeContinuity)
{
    TopoDS_Edge edge1;
    TopoDS_Edge edge2;
    TopoDS_Edge edge3;
    BRep_Builder b;
    BRepTools::Read(edge1, "TestData/checkEdgeContinuity_edge1.brep", b);
    BRepTools::Read(edge2, "TestData/checkEdgeContinuity_edge2.brep", b);
    BRepTools::Read(edge3, "TestData/checkEdgeContinuity_edge3.brep", b);
    ASSERT_EQ(C2, getEdgeContinuity(edge1, edge2));
    ASSERT_EQ(C0, getEdgeContinuity(edge2, edge3));
    ASSERT_EQ(C0, getEdgeContinuity(edge3, edge1));
}

TEST(TiglCommonFunctions, IntersectLinePlane)
{
    gp_Pln plane(gp_Pnt(10., 2., 0.), gp_Dir(0., 1., 0));

    gp_Pnt result;
    ASSERT_EQ(BetweenPoints, IntersectLinePlane(gp_Pnt(0., 0., 0.), gp_Pnt(0., 4., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(0., 2., 0)), 1e-10);

    ASSERT_EQ(OutsideBefore, IntersectLinePlane(gp_Pnt(1., 3., 0.), gp_Pnt(1., 4., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(1., 2., 0)), 1e-10);

    ASSERT_EQ(OutsideAfter, IntersectLinePlane(gp_Pnt(1., 0., 0.), gp_Pnt(1., 1., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(1., 2., 0)), 1e-10);

    ASSERT_EQ(NoIntersection, IntersectLinePlane(gp_Pnt(1., 3., 0.), gp_Pnt(10., 3., 0.), plane, result));
}

TEST(TiglCommonFunctions, IsPointInsideShape)
{
    TopoDS_Shape box = BRepPrimAPI_MakeBox(1., 1., 1).Solid();

    EXPECT_TRUE(IsPointInsideShape(box, gp_Pnt(0.5, 0.5, 0.5)));
    EXPECT_TRUE(IsPointInsideShape(box, gp_Pnt(1.0, 0.5, 0.5)));

    EXPECT_FALSE(IsPointInsideShape(box, gp_Pnt(1.5, 0.5, 0.5)));

    TopoDS_Shape boxrev = box.Reversed();

    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(0.5, 0.5, 0.5)));
    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(1.0, 0.5, 0.5)));

    EXPECT_FALSE(IsPointInsideShape(boxrev, gp_Pnt(1.5, 0.5, 0.5)));

    // check tolerance of 1e-3
    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(1.0009, 0.5, 0.5)));
    EXPECT_FALSE(IsPointInsideShape(boxrev, gp_Pnt(1.0011, 0.5, 0.5)));

    // The function requires a solid, else it will throw
    TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(gp_Pnt(10., 10., 10.));
    EXPECT_THROW(IsPointInsideShape(v, gp_Pnt(0., 0., 0.)), tigl::CTiglError);
}

TEST(TiglCommonFunctions, tiglCheckPointInside_api)
{
    TixiDocumentHandle tixiSimpleWingHandle = -1;
    TiglCPACSConfigurationHandle tiglSimpleWingHandle = -1;

    ReturnCode tixiRet = tixiOpenDocument("TestData/simpletest.cpacs.xml", &tixiSimpleWingHandle);
    ASSERT_EQ (SUCCESS, tixiRet);

    TiglReturnCode tiglRet = tiglOpenCPACSConfiguration(tixiSimpleWingHandle, "Cpacs2Test", &tiglSimpleWingHandle);
    ASSERT_EQ(TIGL_SUCCESS, tiglRet);

    TiglBoolean isInside = TIGL_FALSE;

    ASSERT_EQ(TIGL_SUCCESS, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "segmentD150_Fuselage_1Segment2ID", &isInside));
    EXPECT_EQ(TIGL_TRUE, isInside);

    ASSERT_EQ(TIGL_SUCCESS, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 2., "segmentD150_Fuselage_1Segment2ID", &isInside));
    EXPECT_EQ(TIGL_FALSE, isInside);

    // test errors
    EXPECT_EQ(TIGL_UID_ERROR, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "wrongUID", &isInside));
    EXPECT_EQ(TIGL_NOT_FOUND, tiglCheckPointInside(-1, 0., 0., 0., "wrongUID", &isInside));
    EXPECT_EQ(TIGL_NULL_POINTER, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., NULL, &isInside));
    EXPECT_EQ(TIGL_NULL_POINTER, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "wrongUID", NULL));

}

TEST(TiglCommonFunctions, LinspaceWithBreaks)
{
    std::vector<double> breaks;
    breaks.push_back(0.25);
    breaks.push_back(0.49);
    breaks.push_back(0.62);
    breaks.push_back(0.);
    breaks.push_back(1.0);
    std::vector<double> res = LinspaceWithBreaks(0., 1., 11, breaks);
    ASSERT_EQ(12, res.size());
    EXPECT_NEAR(0.00, res[0], 1e-10);
    EXPECT_NEAR(0.10, res[1], 1e-10);
    EXPECT_NEAR(0.20, res[2], 1e-10);
    EXPECT_NEAR(0.25, res[3], 1e-10);
    EXPECT_NEAR(0.30, res[4], 1e-10);
    EXPECT_NEAR(0.40, res[5], 1e-10);
    EXPECT_NEAR(0.49, res[6], 1e-10);
    EXPECT_NEAR(0.62, res[7], 1e-10);
    EXPECT_NEAR(0.70, res[8], 1e-10);
    EXPECT_NEAR(0.80, res[9], 1e-10);
    EXPECT_NEAR(0.90, res[10], 1e-10);
    EXPECT_NEAR(1.00, res[11], 1e-10);
}

TEST(TiglCommonFunctions, ReplaceAdjacentWith)
{
    auto is_adjacent = [](int v1, int v2) {
        return v1 + 1 == v2;
    };

    auto merged = [](int v1, int v2) {
        return v2;
    };

    std::list<int> a = {1, 2, 3, 10};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({3, 10}, a));

    a = {1, 2, 5, 6, 7, 9, 11, 23,24};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({2, 7, 9, 11, 24}, a));

    a = {5};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({5}, a));

    a = {5, 6};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({6}, a));

    a = {};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({}, a));

}
<commit_msg>Style change<commit_after>/*
* Copyright (C) 2015 German Aerospace Center (DLR/SC)
*
* Created: 2015-05-08 Martin Siggel <Martin.Siggel@dlr.de>
*
* 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 "tigl.h"
#include "tiglcommonfunctions.h"
#include "test.h"
#include <BRep_Builder.hxx>
#include <BRepTools.hxx>

#include <gp_Pln.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>

#include <list>

TEST(TiglCommonFunctions, isPathRelative)
{
    ASSERT_TRUE(IsPathRelative("./test.txt"));

    ASSERT_TRUE(IsPathRelative("test.txt"));

    ASSERT_TRUE(IsPathRelative("../test.txt"));

    // check absolute paths
#ifdef WIN32
    ASSERT_FALSE(IsPathRelative("d:/data/test.txt"));
#else
    ASSERT_FALSE(IsPathRelative("/usr/bin/test.txt"));
#endif
}

TEST(TiglCommonFunctions, isFileReadable)
{
    ASSERT_TRUE(IsFileReadable("TestData/nacelle.stp"));
    ASSERT_FALSE(IsFileReadable("invalidfile.txt"));
}

TEST(TiglCommonFunctions, getEdgeContinuity)
{
    TopoDS_Edge edge1;
    TopoDS_Edge edge2;
    TopoDS_Edge edge3;
    BRep_Builder b;
    BRepTools::Read(edge1, "TestData/checkEdgeContinuity_edge1.brep", b);
    BRepTools::Read(edge2, "TestData/checkEdgeContinuity_edge2.brep", b);
    BRepTools::Read(edge3, "TestData/checkEdgeContinuity_edge3.brep", b);
    ASSERT_EQ(C2, getEdgeContinuity(edge1, edge2));
    ASSERT_EQ(C0, getEdgeContinuity(edge2, edge3));
    ASSERT_EQ(C0, getEdgeContinuity(edge3, edge1));
}

TEST(TiglCommonFunctions, IntersectLinePlane)
{
    gp_Pln plane(gp_Pnt(10., 2., 0.), gp_Dir(0., 1., 0));

    gp_Pnt result;
    ASSERT_EQ(BetweenPoints, IntersectLinePlane(gp_Pnt(0., 0., 0.), gp_Pnt(0., 4., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(0., 2., 0)), 1e-10);

    ASSERT_EQ(OutsideBefore, IntersectLinePlane(gp_Pnt(1., 3., 0.), gp_Pnt(1., 4., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(1., 2., 0)), 1e-10);

    ASSERT_EQ(OutsideAfter, IntersectLinePlane(gp_Pnt(1., 0., 0.), gp_Pnt(1., 1., 0.), plane, result));
    ASSERT_NEAR(0., result.Distance(gp_Pnt(1., 2., 0)), 1e-10);

    ASSERT_EQ(NoIntersection, IntersectLinePlane(gp_Pnt(1., 3., 0.), gp_Pnt(10., 3., 0.), plane, result));
}

TEST(TiglCommonFunctions, IsPointInsideShape)
{
    TopoDS_Shape box = BRepPrimAPI_MakeBox(1., 1., 1).Solid();

    EXPECT_TRUE(IsPointInsideShape(box, gp_Pnt(0.5, 0.5, 0.5)));
    EXPECT_TRUE(IsPointInsideShape(box, gp_Pnt(1.0, 0.5, 0.5)));

    EXPECT_FALSE(IsPointInsideShape(box, gp_Pnt(1.5, 0.5, 0.5)));

    TopoDS_Shape boxrev = box.Reversed();

    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(0.5, 0.5, 0.5)));
    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(1.0, 0.5, 0.5)));

    EXPECT_FALSE(IsPointInsideShape(boxrev, gp_Pnt(1.5, 0.5, 0.5)));

    // check tolerance of 1e-3
    EXPECT_TRUE(IsPointInsideShape(boxrev, gp_Pnt(1.0009, 0.5, 0.5)));
    EXPECT_FALSE(IsPointInsideShape(boxrev, gp_Pnt(1.0011, 0.5, 0.5)));

    // The function requires a solid, else it will throw
    TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(gp_Pnt(10., 10., 10.));
    EXPECT_THROW(IsPointInsideShape(v, gp_Pnt(0., 0., 0.)), tigl::CTiglError);
}

TEST(TiglCommonFunctions, tiglCheckPointInside_api)
{
    TixiDocumentHandle tixiSimpleWingHandle = -1;
    TiglCPACSConfigurationHandle tiglSimpleWingHandle = -1;

    ReturnCode tixiRet = tixiOpenDocument("TestData/simpletest.cpacs.xml", &tixiSimpleWingHandle);
    ASSERT_EQ (SUCCESS, tixiRet);

    TiglReturnCode tiglRet = tiglOpenCPACSConfiguration(tixiSimpleWingHandle, "Cpacs2Test", &tiglSimpleWingHandle);
    ASSERT_EQ(TIGL_SUCCESS, tiglRet);

    TiglBoolean isInside = TIGL_FALSE;

    ASSERT_EQ(TIGL_SUCCESS, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "segmentD150_Fuselage_1Segment2ID", &isInside));
    EXPECT_EQ(TIGL_TRUE, isInside);

    ASSERT_EQ(TIGL_SUCCESS, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 2., "segmentD150_Fuselage_1Segment2ID", &isInside));
    EXPECT_EQ(TIGL_FALSE, isInside);

    // test errors
    EXPECT_EQ(TIGL_UID_ERROR, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "wrongUID", &isInside));
    EXPECT_EQ(TIGL_NOT_FOUND, tiglCheckPointInside(-1, 0., 0., 0., "wrongUID", &isInside));
    EXPECT_EQ(TIGL_NULL_POINTER, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., nullptr, &isInside));
    EXPECT_EQ(TIGL_NULL_POINTER, tiglCheckPointInside(tiglSimpleWingHandle, 0., 0., 0., "wrongUID", nullptr));

}

TEST(TiglCommonFunctions, LinspaceWithBreaks)
{
    std::vector<double> breaks;
    breaks.push_back(0.25);
    breaks.push_back(0.49);
    breaks.push_back(0.62);
    breaks.push_back(0.);
    breaks.push_back(1.0);
    std::vector<double> res = LinspaceWithBreaks(0., 1., 11, breaks);
    ASSERT_EQ(12, res.size());
    EXPECT_NEAR(0.00, res[0], 1e-10);
    EXPECT_NEAR(0.10, res[1], 1e-10);
    EXPECT_NEAR(0.20, res[2], 1e-10);
    EXPECT_NEAR(0.25, res[3], 1e-10);
    EXPECT_NEAR(0.30, res[4], 1e-10);
    EXPECT_NEAR(0.40, res[5], 1e-10);
    EXPECT_NEAR(0.49, res[6], 1e-10);
    EXPECT_NEAR(0.62, res[7], 1e-10);
    EXPECT_NEAR(0.70, res[8], 1e-10);
    EXPECT_NEAR(0.80, res[9], 1e-10);
    EXPECT_NEAR(0.90, res[10], 1e-10);
    EXPECT_NEAR(1.00, res[11], 1e-10);
}

TEST(TiglCommonFunctions, ReplaceAdjacentWith)
{
    auto is_adjacent = [](int v1, int v2) {
        return v1 + 1 == v2;
    };

    auto merged = [](int /* v1 */, int v2) {
        return v2;
    };

    std::list<int> a = {1, 2, 3, 10};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({3, 10}, a));

    a = {1, 2, 5, 6, 7, 9, 11, 23, 24};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({2, 7, 9, 11, 24}, a));

    a = {5};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({5}, a));

    a = {5, 6};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({6}, a));

    a = {};
    ReplaceAdjacentWithMerged(a, is_adjacent, merged);
    EXPECT_TRUE(ArraysMatch({}, a));

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "ut_resetapplet.h"
#include "resetapplet.h"
#include "resetwidget.h"

#include "resetbrief.h"

#include <dcpwidgettypes.h>
#include <dcpbrief.h>

#include <mdesktopentry.h>
#include <MApplication>
#include <MAction>
#include <MDialog>
#include <QVector>

#define DEBUG
#include "../../src/debug.h"

/******************************************************************************
 * Stubbing the system() C library function here.
 */
static QString lastExecutedCommand;
static int     commandSuccess;

int
system (
        const char *command)
{
    SYS_DEBUG ("*** command = %s", command);

    lastExecutedCommand = command;
    return commandSuccess;
}

static bool dialogAnswerYes = false;
static bool dialogAnswerNo = false;
static bool dialogExecuted = false;

int
MDialog::exec (MWindow *window)
{
    SYS_DEBUG ("");

    Q_UNUSED (window);

    dialogExecuted = true;

    if (dialogAnswerYes)
        return M::YesButton;
    if (dialogAnswerNo)
        return M::NoButton;

    return 0;
}

/******************************************************************************
 * Ut_ResetApplet implementation.
 */
void
Ut_ResetApplet::init()
{
}

void
Ut_ResetApplet::cleanup()
{
}

static int argc = 1;
static char *app_name = (char*) "./Ut_ResetApplet";

void
Ut_ResetApplet::initTestCase()
{
    m_App = new MApplication (argc, &app_name);
    m_Applet = new ResetApplet;

    QVERIFY (!m_Applet->m_MainWidget);
    m_Applet->init ();

    /*
     * Testing if the widget is not created yet.
     */
    QVERIFY (!m_Applet->m_MainWidget);
}

void
Ut_ResetApplet::cleanupTestCase()
{
    delete m_Applet;
    m_App->deleteLater ();
}

void
Ut_ResetApplet::testTitle ()
{
    QString title = m_Applet->title();
    QVERIFY (!title.isEmpty());
}

void
Ut_ResetApplet::testConstructWidget ()
{
    ResetWidget *widget;
    bool         backAccepted;

    /*
     * We check if we got a NULL pointer for the invalid window ID.
     */
    widget = (ResetWidget *) m_Applet->constructWidget (3);
    QVERIFY (!widget);

    /*
     * Testing if the applet creates a widget the first time.
     */
    widget = (ResetWidget *) m_Applet->constructWidget (0);
    QVERIFY (widget);
    QVERIFY (m_Applet->m_MainWidget == widget);

    /*
     * Testing if the widget accepts the back. Our applets always accept back.
     */
    backAccepted = widget->back();
    QVERIFY (backAccepted);

    /*
     * Testing the ResetWidget. We could write a separate unit test, but it
     * would be very primitive...
     */
    // Restore with 'no' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = false;
    dialogAnswerNo = true;
    dialogExecuted = false;
    widget->restoreActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "");
    QVERIFY (dialogExecuted);

    // Restore with 'yes' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = true;
    dialogAnswerNo = false;
    dialogExecuted = false;
    widget->restoreActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --rfs");
    QVERIFY (dialogExecuted);

    // Clear with 'no' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = false;
    dialogAnswerNo = true;
    dialogExecuted = false;
    widget->clearActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "");
    QVERIFY (dialogExecuted);

    // Clear with 'yes' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = true;
    dialogAnswerNo = false;
    dialogExecuted = false;
    widget->clearActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --cud");
    QVERIFY (dialogExecuted);

    /*
     * Testing if the applet knows about the destruction of the widget.
     */
    delete widget;
    QVERIFY (!m_Applet->m_MainWidget);
}

void
Ut_ResetApplet::testMenuItems ()
{
    QVector<MAction*> items = m_Applet->viewMenuItems ();

    QVERIFY (items.size() == 1);
}

void
Ut_ResetApplet::testConstructbrief ()
{
    ResetBrief *brief1 = (ResetBrief *) m_Applet->constructBrief(0);
    QString   iconName;
    QString   text;

    QVERIFY (brief1);
    QVERIFY (brief1->widgetTypeID() == DcpWidgetType::Label);

    iconName = brief1->icon ();
    QVERIFY (iconName.isEmpty());

    text = brief1->valueText ();
    QVERIFY (text.isEmpty());

    // FIXME: Why does this method has an argument, it must be some leftover
    // code. Also: we should check if the signal is emitted.
    delete brief1;
}

/*!
 * Testing the whole functionality of the ResetBusinesslogic. We could write a
 * separate unit test for this class, but it is very primitive, so we just do
 * the job here.
 */
void
Ut_ResetApplet::testResetBusinessLogic ()
{
    // So we get a better coverage we use an error code sometimes.
    commandSuccess = 3;

    m_Applet->m_ResetBusinessLogic->performRestoreSettings ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --rfs");

    m_Applet->m_ResetBusinessLogic->performClearData ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --cud");
}

QTEST_APPLESS_MAIN(Ut_ResetApplet)

<commit_msg>Changes: ut_resetapplet: following the implementation changes<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "ut_resetapplet.h"
#include "resetapplet.h"
#include "resetwidget.h"

#include "resetbrief.h"

#include <dcpwidgettypes.h>
#include <dcpbrief.h>

#include <mdesktopentry.h>
#include <MApplication>
#include <MAction>
#include <MDialog>
#include <QVector>

#define DEBUG
#include "../../src/debug.h"

/******************************************************************************
 * Stubbing the system() C library function here.
 */
static QString lastExecutedCommand;
static int     commandSuccess;

int
system (
        const char *command)
{
    SYS_DEBUG ("*** command = %s", command);

    lastExecutedCommand = command;
    return commandSuccess;
}

static bool dialogAnswerYes = false;
static bool dialogAnswerNo = false;
static bool dialogExecuted = false;

int
MDialog::exec (MWindow *window)
{
    SYS_DEBUG ("");

    Q_UNUSED (window);

    dialogExecuted = true;

    if (dialogAnswerYes)
        return M::YesButton;
    if (dialogAnswerNo)
        return M::NoButton;

    return 0;
}

/******************************************************************************
 * Ut_ResetApplet implementation.
 */
void
Ut_ResetApplet::init()
{
}

void
Ut_ResetApplet::cleanup()
{
}

static int argc = 1;
static char *app_name = (char*) "./Ut_ResetApplet";

void
Ut_ResetApplet::initTestCase()
{
    m_App = new MApplication (argc, &app_name);
    m_Applet = new ResetApplet;

    QVERIFY (!m_Applet->m_MainWidget);
    m_Applet->init ();

    /*
     * Testing if the widget is not created yet.
     */
    QVERIFY (!m_Applet->m_MainWidget);
}

void
Ut_ResetApplet::cleanupTestCase()
{
    delete m_Applet;
    m_App->deleteLater ();
}

void
Ut_ResetApplet::testTitle ()
{
    QString title = m_Applet->title();
    QVERIFY (!title.isEmpty());
}

void
Ut_ResetApplet::testConstructWidget ()
{
    ResetWidget *widget;
    bool         backAccepted;

    /*
     * We check if we got a NULL pointer for the invalid window ID.
     */
    widget = (ResetWidget *) m_Applet->constructWidget (3);
    QVERIFY (!widget);

    /*
     * Testing if the applet creates a widget the first time.
     */
    widget = (ResetWidget *) m_Applet->constructWidget (0);
    QVERIFY (widget);
    QVERIFY (m_Applet->m_MainWidget == widget);

    /*
     * Testing if the widget accepts the back. Our applets always accept back.
     */
    backAccepted = widget->back();
    QVERIFY (backAccepted);

    /*
     * Testing the ResetWidget. We could write a separate unit test, but it
     * would be very primitive...
     */
    // Restore with 'no' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = false;
    dialogAnswerNo = true;
    dialogExecuted = false;
    widget->restoreActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "");
    QVERIFY (dialogExecuted);

    // Restore with 'yes' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = true;
    dialogAnswerNo = false;
    dialogExecuted = false;
    widget->restoreActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --rfs");
    QVERIFY (dialogExecuted);

    // Clear with 'no' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = false;
    dialogAnswerNo = true;
    dialogExecuted = false;
    widget->clearActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "");
    QVERIFY (dialogExecuted);

    // Clear with 'yes' as answer.
    lastExecutedCommand = "";
    commandSuccess = 0;
    dialogAnswerYes = true;
    dialogAnswerNo = false;
    dialogExecuted = false;
    widget->clearActivated ();
    widget->doTheWork ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --cud-reset");
    QVERIFY (dialogExecuted);

    /*
     * Testing if the applet knows about the destruction of the widget.
     */
    delete widget;
    QVERIFY (!m_Applet->m_MainWidget);
}

void
Ut_ResetApplet::testMenuItems ()
{
    QVector<MAction*> items = m_Applet->viewMenuItems ();

    QVERIFY (items.size() == 1);
}

void
Ut_ResetApplet::testConstructbrief ()
{
    ResetBrief *brief1 = (ResetBrief *) m_Applet->constructBrief(0);
    QString   iconName;
    QString   text;

    QVERIFY (brief1);
    QVERIFY (brief1->widgetTypeID() == DcpWidgetType::Label);

    iconName = brief1->icon ();
    QVERIFY (iconName.isEmpty());

    text = brief1->valueText ();
    QVERIFY (text.isEmpty());

    // FIXME: Why does this method has an argument, it must be some leftover
    // code. Also: we should check if the signal is emitted.
    delete brief1;
}

/*!
 * Testing the whole functionality of the ResetBusinesslogic. We could write a
 * separate unit test for this class, but it is very primitive, so we just do
 * the job here.
 */
void
Ut_ResetApplet::testResetBusinessLogic ()
{
    // So we get a better coverage we use an error code sometimes.
    commandSuccess = 3;

    m_Applet->m_ResetBusinessLogic->performRestoreSettings ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --rfs");

    m_Applet->m_ResetBusinessLogic->performClearData ();
    QVERIFY (lastExecutedCommand == "/usr/sbin/clean-device.sh --cud-reset");
}

QTEST_APPLESS_MAIN(Ut_ResetApplet)

<|endoftext|>