Merge pull request #1044 from imvu/embind_update

Embind update
This commit is contained in:
Alon Zakai 2013-04-16 14:03:43 -07:00
Родитель 3cbdfcc318 8ae67d7642
Коммит 985765d9a5
13 изменённых файлов: 7899 добавлений и 1565 удалений

13
AUTHORS
Просмотреть файл

@ -24,7 +24,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Pierre Renaux <pierre@talansoft.com>
* Brian Anderson <banderson@mozilla.com>
* Jon Bardin <diclophis@gmail.com>
* Jukka Jylänki <jujjyl@gmail.com>
* Jukka Jylänki <jujjyl@gmail.com>
* Aleksander Guryanov <caiiiycuk@gmail.com>
* Chad Austin <chad@chadaustin.me> (copyright owned by IMVU)
* nandhp <nandhp@gmail.com>
@ -46,7 +46,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Anthony Liot <wolfviking0@yahoo.com>
* Michael Riss <Michael.Riss@gmx.de>
* Jasper St. Pierre <jstpierre@mecheye.net>
* Manuel Schölling <manuel.schoelling@gmx.de>
* Manuel Schölling <manuel.schoelling@gmx.de>
* Bruce Mitchener, Jr. <bruce.mitchener@gmail.com>
* Michael Bishop <mbtyke@gmail.com>
* Roger Braun <roger@rogerbraun.net>
@ -57,9 +57,14 @@ a license to everyone to use it as detailed in LICENSE.)
* Ting-Yuan Huang <thuang@mozilla.com>
* Joshua Granick <jgranick@blackberry.com>
* Felix H. Dahlke <fhd@ubercode.de>
* Éloi Rivard <azmeuk@gmail.com>
* Éloi Rivard <azmeuk@gmail.com>
* Alexander Gladysh <ag@logiceditor.com>
* Arlo Breault <arlolra@gmail.com>
* Jacob Lee <artdent@gmail.com> (copyright owned by Google, Inc.)
* Joe Lee <jlee@imvu.com> (copyright owned by IMVU)
* Andy Friesen <andy@imvu.com> (copyright owned by IMVU)
* Bill Welden <bwelden@imvu.com> (copyright owned by IMVU)
* Michael Ey <mey@imvu.com> (copyright owned by IMVU)
* Llorens Marti Garcia <lgarcia@imvu.com> (copyright owned by IMVU)
* Jinsuck Kim <jkim@imvu.com> (copyright owned by IMVU)
* Todd Lee <tlee@imvu.com> (copyright owned by IMVU)

1581
src/embind/embind.js Normal file → Executable file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

147
src/embind/emval.js Normal file → Executable file
Просмотреть файл

@ -10,7 +10,23 @@ var _emval_free_list = [];
/** @expose */
Module.count_emval_handles = function() {
return _emval_handle_array.length;
var count = 0;
for (var i = 0; i < _emval_handle_array.length; ++i) {
if (_emval_handle_array[i] !== undefined) {
++count;
}
}
return count;
};
/** @expose */
Module.get_first_emval = function() {
for (var i = 0; i < _emval_handle_array.length; ++i) {
if (_emval_handle_array[i] !== undefined) {
return _emval_handle_array[i];
}
}
return null;
};
// Private C++ API
@ -19,6 +35,7 @@ function __emval_register(value) {
var handle = _emval_free_list.length ?
_emval_free_list.pop() :
_emval_handle_array.length;
_emval_handle_array[handle] = {refcount: 1, value: value};
return handle;
}
@ -40,38 +57,91 @@ function __emval_decref(handle) {
}
}
function __emval_new_array() {
return __emval_register([]);
}
function __emval_new_object() {
return __emval_register({});
}
function __emval_new_long(value) {
return __emval_register(value);
function __emval_undefined() {
return __emval_register(undefined);
}
function __emval_new_cstring(str) {
return __emval_register(Pointer_stringify(str));
function __emval_null() {
return __emval_register(null);
}
function __emval_get_property(handle, k) {
k = Pointer_stringify(k);
return __emval_register(_emval_handle_array[handle].value[k]);
function __emval_new_cstring(v) {
return __emval_register(Pointer_stringify(v));
}
function __emval_get_property_by_long(handle, k) {
return __emval_register(_emval_handle_array[handle].value[k]);
function __emval_take_value(type, v) {
type = requireRegisteredType(type, '_emval_take_value');
v = type.fromWireType(v);
return __emval_register(v);
}
function __emval_get_property_by_unsigned_long(handle, k) {
return __emval_register(_emval_handle_array[handle].value[k]);
var __newers = {}; // arity -> function
function __emval_new(handle, argCount, argTypes) {
var args = parseParameters(
argCount,
argTypes,
Array.prototype.slice.call(arguments, 3));
// Alas, we are forced to use operator new until WebKit enables
// constructing typed arrays without new.
// In WebKit, Uint8Array(10) throws an error.
// In every other browser, it's identical to new Uint8Array(10).
var newer = __newers[argCount];
if (!newer) {
var parameters = new Array(argCount);
for (var i = 0; i < argCount; ++i) {
parameters[i] = 'a' + i;
}
/*jshint evil:true*/
newer = __newers[argCount] = new Function(
['c'].concat(parameters),
"return new c(" + parameters.join(',') + ");");
}
var constructor = _emval_handle_array[handle].value;
var obj = newer.apply(undefined, [constructor].concat(args));
/*
// implement what amounts to operator new
function dummy(){}
dummy.prototype = constructor.prototype;
var obj = new constructor;
var rv = constructor.apply(obj, args);
if (typeof rv === 'object') {
obj = rv;
}
*/
return __emval_register(obj);
}
function __emval_set_property(handle, k, value) {
k = Pointer_stringify(k);
_emval_handle_array[handle].value[k] = _emval_handle_array[value].value;
// appease jshint (technically this code uses eval)
var global = (function(){return Function;})()('return this')();
function __emval_get_global(name) {
name = Pointer_stringify(name);
return __emval_register(global[name]);
}
function __emval_set_property_by_int(handle, k, value) {
_emval_handle_array[handle].value[k] = _emval_handle_array[value].value;
function __emval_get_module_property(name) {
name = Pointer_stringify(name);
return __emval_register(Module[name]);
}
function __emval_get_property(handle, key) {
return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]);
}
function __emval_set_property(handle, key, value) {
_emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value;
}
function __emval_as(handle, returnType) {
@ -81,31 +151,46 @@ function __emval_as(handle, returnType) {
return returnType.toWireType(destructors, _emval_handle_array[handle].value);
}
function __emval_call(handle, argCount, argTypes) {
var args = Array.prototype.slice.call(arguments, 3);
var fn = _emval_handle_array[handle].value;
function parseParameters(argCount, argTypes, argWireTypes) {
var a = new Array(argCount);
for (var i = 0; i < argCount; ++i) {
var argType = requireRegisteredType(
HEAP32[(argTypes >> 2) + i],
"parameter " + i);
a[i] = argType.fromWireType(args[i]);
a[i] = argType.fromWireType(argWireTypes[i]);
}
var rv = fn.apply(undefined, a);
return a;
}
function __emval_call(handle, argCount, argTypes) {
var fn = _emval_handle_array[handle].value;
var args = parseParameters(
argCount,
argTypes,
Array.prototype.slice.call(arguments, 3));
var rv = fn.apply(undefined, args);
return __emval_register(rv);
}
function __emval_call_method(handle, name, argCount, argTypes) {
name = Pointer_stringify(name);
var args = Array.prototype.slice.call(arguments, 4);
var args = parseParameters(
argCount,
argTypes,
Array.prototype.slice.call(arguments, 4));
var obj = _emval_handle_array[handle].value;
var a = new Array(argCount);
for (var i = 0; i < argCount; ++i) {
var argType = requireRegisteredType(
HEAP32[(argTypes >> 2) + i],
"parameter " + i);
a[i] = argType.fromWireType(args[i]);
}
var rv = obj[name].apply(obj, a);
var rv = obj[name].apply(obj, args);
return __emval_register(rv);
}
function __emval_call_void_method(handle, name, argCount, argTypes) {
name = Pointer_stringify(name);
var args = parseParameters(
argCount,
argTypes,
Array.prototype.slice.call(arguments, 4));
var obj = _emval_handle_array[handle].value;
obj[name].apply(obj, args);
}

1367
system/include/emscripten/bind.h Normal file → Executable file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,6 +2,7 @@
#include <stdint.h> // uintptr_t
#include <emscripten/wire.h>
#include <vector>
namespace emscripten {
namespace internal {
@ -11,49 +12,104 @@ namespace emscripten {
void _emval_incref(EM_VAL value);
void _emval_decref(EM_VAL value);
EM_VAL _emval_new_array();
EM_VAL _emval_new_object();
EM_VAL _emval_new_long(long value);
EM_VAL _emval_new_cstring(const char* str);
EM_VAL _emval_get_property(EM_VAL object, const char* key);
EM_VAL _emval_get_property_by_long(EM_VAL object, long key);
EM_VAL _emval_get_property_by_unsigned_long(EM_VAL object, unsigned long key);
void _emval_set_property(EM_VAL object, const char* key, EM_VAL value);
void _emval_set_property_by_int(EM_VAL object, long key, EM_VAL value);
void _emval_as(EM_VAL value, emscripten::internal::TypeID returnType);
EM_VAL _emval_undefined();
EM_VAL _emval_null();
EM_VAL _emval_new_cstring(const char*);
void _emval_take_value(TYPEID type/*, ...*/);
EM_VAL _emval_new(
EM_VAL value,
unsigned argCount,
internal::TYPEID argTypes[]
/*, ... */);
EM_VAL _emval_get_global(const char* name);
EM_VAL _emval_get_module_property(const char* name);
EM_VAL _emval_get_property(EM_VAL object, EM_VAL key);
void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value);
void _emval_as(EM_VAL value, TYPEID returnType);
EM_VAL _emval_call(
EM_VAL value,
unsigned argCount,
internal::TypeID argTypes[]
internal::TYPEID argTypes[]
/*, ... */);
EM_VAL _emval_call_method(
EM_VAL value,
const char* methodName,
unsigned argCount,
internal::TypeID argTypes[]
internal::TYPEID argTypes[]
/*, ... */);
void _emval_call_void_method(
EM_VAL value,
const char* methodName,
unsigned argCount,
internal::TYPEID argTypes[]
/*, ...*/);
}
}
class val {
public:
// missing operators:
// * delete
// * in
// * instanceof
// * typeof
// * ! ~ - + ++ --
// * * / %
// * + -
// * << >> >>>
// * < <= > >=
// * == != === !==
// * & ^ | && || ?:
//
// exposing void, comma, and conditional is unnecessary
// same with: = += -= *= /= %= <<= >>= >>>= &= ^= |=
static val array() {
return val(internal::_emval_new_array());
}
static val object() {
return val(internal::_emval_new_object());
};
}
static val undefined() {
return val(internal::_emval_undefined());
}
static val null() {
return val(internal::_emval_null());
}
static val take_ownership(internal::EM_VAL e) {
return val(e);
}
explicit val(long l)
: handle(internal::_emval_new_long(l))
{}
static val global(const char* name) {
return val(internal::_emval_get_global(name));
}
explicit val(const char* str)
: handle(internal::_emval_new_cstring(str))
{}
static val module_property(const char* name) {
return val(internal::_emval_get_module_property(name));
}
template<typename T>
explicit val(const T& value) {
typedef internal::BindingType<T> BT;
auto taker = reinterpret_cast<internal::EM_VAL (*)(internal::TYPEID, typename BT::WireType)>(&internal::_emval_take_value);
handle = taker(internal::TypeID<T>::get(), BT::toWireType(value));
}
val() = delete;
val(const char* v)
: handle(internal::_emval_new_cstring(v))
{}
val(const val& v)
: handle(v.handle)
{
@ -71,82 +127,114 @@ namespace emscripten {
return *this;
}
val get(const char* key) const {
return val(internal::_emval_get_property(handle, key));
bool hasOwnProperty(const char* key) const {
return val::global("Object")["prototype"]["hasOwnProperty"].call("call", *this, val(key)).as<bool>();
}
val get(int key) const {
return get(long(key));
}
template<typename... Args>
val new_(Args... args) const {
using namespace internal;
val get(unsigned int key) const {
typedef unsigned long T;
return get(T(key));
}
val get(long key) const {
return val(internal::_emval_get_property_by_long(handle, key));
}
val get(unsigned long key) const {
return val(internal::_emval_get_property_by_unsigned_long(handle, key));
}
void set(const char* key, val v) {
internal::_emval_set_property(handle, key, v.handle);
}
void set(long key, val v) {
internal::_emval_set_property_by_int(handle, key, v.handle);
}
template<typename ...Args>
val operator()(Args... args) {
internal::ArgTypeList<Args...> argList;
typedef internal::EM_VAL (*TypedCall)(
internal::EM_VAL,
WithPolicies<>::ArgTypeList<Args...> argList;
// todo: this is awfully similar to operator(), can we
// merge them somehow?
typedef EM_VAL (*TypedNew)(
EM_VAL,
unsigned,
internal::TypeID argTypes[],
typename internal::BindingType<Args>::WireType...);
TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call);
TYPEID argTypes[],
typename BindingType<Args>::WireType...);
TypedNew typedNew = reinterpret_cast<TypedNew>(&_emval_new);
return val(
typedNew(
handle,
argList.count,
argList.types,
toWireType(args)...));
}
template<typename T>
val operator[](const T& key) const {
return val(internal::_emval_get_property(handle, val(key).handle));
}
template<typename T>
void set(const T& key, val v) {
internal::_emval_set_property(handle, val(key).handle, v.handle);
}
template<typename... Args>
val operator()(Args... args) {
using namespace internal;
WithPolicies<>::ArgTypeList<Args...> argList;
typedef EM_VAL (*TypedCall)(
EM_VAL,
unsigned,
TYPEID argTypes[],
typename BindingType<Args>::WireType...);
TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call);
return val(
typedCall(
handle,
argList.count,
argList.types,
internal::toWireType(args)...));
toWireType(args)...));
}
template<typename ...Args>
val call(const char* name, Args... args) {
internal::ArgTypeList<Args...> argList;
typedef internal::EM_VAL (*TypedCall)(
internal::EM_VAL,
val call(const char* name, Args... args) const {
using namespace internal;
WithPolicies<>::ArgTypeList<Args...> argList;
typedef EM_VAL (*TypedCall)(
EM_VAL,
const char* name,
unsigned,
internal::TypeID argTypes[],
typename internal::BindingType<Args>::WireType...);
TypedCall typedCall = reinterpret_cast<TypedCall>(&internal::_emval_call_method);
TYPEID argTypes[],
typename BindingType<Args>::WireType...);
TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_method);
return val(
typedCall(
handle,
name,
argList.count,
argList.types,
internal::toWireType(args)...));
toWireType(args)...));
}
template<typename ...Args>
void call_void(const char* name, Args... args) const {
using namespace internal;
WithPolicies<>::ArgTypeList<Args...> argList;
typedef void (*TypedCall)(
EM_VAL,
const char* name,
unsigned,
TYPEID argTypes[],
typename BindingType<Args>::WireType...);
TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call_void_method);
return typedCall(
handle,
name,
argList.count,
argList.types,
toWireType(args)...);
}
template<typename T>
T as() const {
typedef internal::BindingType<T> BT;
using namespace internal;
typedef BindingType<T> BT;
typedef typename BT::WireType (*TypedAs)(
internal::EM_VAL value,
emscripten::internal::TypeID returnType);
TypedAs typedAs = reinterpret_cast<TypedAs>(&internal::_emval_as);
EM_VAL value,
TYPEID returnType);
TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as);
typename BT::WireType wt = typedAs(handle, internal::getTypeID<T>());
internal::WireDeleter<T> deleter(wt);
typename BT::WireType wt = typedAs(handle, TypeID<T>::get());
WireDeleter<T> deleter(wt);
return BT::fromWireType(wt);
}
@ -170,8 +258,22 @@ namespace emscripten {
return v.handle;
}
static val fromWireType(WireType v) {
return val(v);
return val::take_ownership(v);
}
static void destroy(WireType v) {
}
};
}
template<typename T>
std::vector<T> vecFromJSArray(val v) {
auto l = v["length"].as<unsigned>();
std::vector<T> rv;
for(unsigned i = 0; i < l; ++i) {
rv.push_back(v[i].as<T>());
}
return rv;
};
}

293
system/include/emscripten/wire.h Normal file → Executable file
Просмотреть файл

@ -7,66 +7,110 @@
//
// We'll call the on-the-wire type WireType.
#include <cstdlib>
#include <memory>
#include <string>
namespace emscripten {
namespace internal {
typedef const struct _TypeID* TypeID;
typedef const struct _TYPEID* TYPEID;
// This implementation is technically not legal, as it's not
// required that two calls to typeid produce the same exact
// std::type_info instance. That said, it's likely to work.
// Should it not work in the future: replace TypeID with
// an int, and store all TypeInfo we see in a map, allocating
// new TypeIDs as we add new items to the map.
// std::type_info instance. That said, it's likely to work
// given Emscripten compiles everything into one binary.
// Should it not work in the future: replace TypeID with an
// int, and store all TypeInfo we see in a map, allocating new
// TypeIDs as we add new items to the map.
template<typename T>
inline TypeID getTypeID() {
return reinterpret_cast<TypeID>(&typeid(T));
}
struct TypeID {
static TYPEID get() {
return reinterpret_cast<TYPEID>(&typeid(T));
}
};
// count<>
template<typename T>
struct TypeID<std::unique_ptr<T>> {
static TYPEID get() {
return TypeID<T>::get();
}
};
template<typename... Args>
struct count;
template<typename T>
struct TypeID<T*> {
static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>");
};
template<typename T>
struct AllowedRawPointer {
};
template<typename T>
struct TypeID<AllowedRawPointer<T>> {
static TYPEID get() {
return reinterpret_cast<TYPEID>(&typeid(T*));
}
};
// ExecutePolicies<>
template<typename... Policies>
struct ExecutePolicies;
template<>
struct count<> {
enum { value = 0 };
struct ExecutePolicies<> {
template<typename T, int Index>
struct With {
typedef T type;
};
};
template<typename Policy, typename... Remaining>
struct ExecutePolicies<Policy, Remaining...> {
template<typename T, int Index>
struct With {
typedef typename Policy::template Transform<
typename ExecutePolicies<Remaining...>::template With<T, Index>::type,
Index
>::type type;
};
};
template<typename T, typename... Args>
struct count<T, Args...> {
enum { value = 1 + count<Args...>::value };
};
// ArgTypes<>
// ArgTypeList<>
template<typename... Args>
template<int Index, typename... Args>
struct ArgTypes;
template<>
struct ArgTypes<> {
static void fill(TypeID* argTypes) {
template<int Index>
struct ArgTypes<Index> {
template<typename... Policies>
static void fill(TYPEID* argTypes) {
}
};
template<typename T, typename... Args>
struct ArgTypes<T, Args...> {
static void fill(TypeID* argTypes) {
*argTypes = getTypeID<T>();
return ArgTypes<Args...>::fill(argTypes + 1);
template<int Index, typename T, typename... Remaining>
struct ArgTypes<Index, T, Remaining...> {
template<typename... Policies>
static void fill(TYPEID* argTypes) {
typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type TransformT;
*argTypes = TypeID<TransformT>::get();
return ArgTypes<Index + 1, Remaining...>::template fill<Policies...>(argTypes + 1);
}
};
template<typename... Args>
struct ArgTypeList {
enum { args_count = count<Args...>::value };
// WithPolicies<...>::ArgTypeList<...>
template<typename... Policies>
struct WithPolicies {
template<typename... Args>
struct ArgTypeList {
ArgTypeList() {
count = sizeof...(Args);
ArgTypes<0, Args...>::template fill<Policies...>(types);
}
ArgTypeList() {
count = args_count;
ArgTypes<Args...>::fill(types);
}
unsigned count;
TypeID types[args_count];
unsigned count;
TYPEID types[sizeof...(Args)];
};
};
// BindingType<T>
@ -74,19 +118,18 @@ namespace emscripten {
template<typename T>
struct BindingType;
#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \
template<> \
struct BindingType<type> { \
typedef type WireType; \
\
constexpr static WireType toWireType(type v) { \
return v; \
} \
constexpr static type fromWireType(WireType v) { \
return v; \
} \
static void destroy(WireType) { \
} \
#define EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(type) \
template<> \
struct BindingType<type> { \
typedef type WireType; \
constexpr static WireType toWireType(const type& v) { \
return v; \
} \
constexpr static type fromWireType(WireType v) { \
return v; \
} \
static void destroy(WireType) { \
} \
}
EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char);
@ -120,23 +163,79 @@ namespace emscripten {
template<>
struct BindingType<std::string> {
typedef char* WireType;
static WireType toWireType(std::string v) {
return strdup(v.c_str());
typedef struct {
size_t length;
char data[1]; // trailing data
}* WireType;
static WireType toWireType(const std::string& v) {
WireType wt = (WireType)malloc(sizeof(size_t) + v.length());
wt->length = v.length();
memcpy(wt->data, v.data(), v.length());
return wt;
}
static std::string fromWireType(char* v) {
return std::string(v);
static std::string fromWireType(WireType v) {
return std::string(v->data, v->length);
}
static void destroy(WireType v) {
free(v);
}
};
template<>
struct BindingType<const std::string&> {
typedef char* WireType;
static WireType toWireType(std::string v) {
return strdup(v.c_str());
template<typename T>
struct BindingType<const T> : public BindingType<T> {
};
template<typename T>
struct BindingType<const T&> : public BindingType<T> {
};
template<typename T>
struct BindingType<T&&> {
typedef typename BindingType<T>::WireType WireType;
static WireType toWireType(const T& v) {
return BindingType<T>::toWireType(v);
}
static std::string fromWireType(char* v) {
return std::string(v);
static T fromWireType(WireType wt) {
return BindingType<T>::fromWireType(wt);
}
};
template<typename T>
struct BindingType<T*> {
typedef T* WireType;
static WireType toWireType(T* p) {
return p;
}
static T* fromWireType(WireType wt) {
return wt;
}
};
template<typename T>
struct GenericBindingType {
typedef typename std::remove_reference<T>::type ActualT;
typedef ActualT* WireType;
static WireType toWireType(T v) {
return new T(v);
}
static ActualT& fromWireType(WireType p) {
return *p;
}
static void destroy(WireType p) {
delete p;
}
};
// Is this necessary?
template<typename T>
struct GenericBindingType<std::unique_ptr<T>> {
typedef typename BindingType<T>::WireType WireType;
static WireType toWireType(std::unique_ptr<T> p) {
return BindingType<T>::toWireType(*p);
}
};
@ -150,60 +249,8 @@ namespace emscripten {
static Enum fromWireType(WireType v) {
return v;
}
};
template<typename T>
struct GenericBindingType {
typedef typename std::remove_reference<T>::type ActualT;
typedef ActualT* WireType;
struct Marshaller {
explicit Marshaller(WireType wt)
: wireType(wt)
{}
Marshaller(Marshaller&& wt)
: wireType(wt.wireType)
{
wt.wireType = 0;
}
operator ActualT&() const {
return *wireType;
}
private:
Marshaller() = delete;
Marshaller(const Marshaller&) = delete;
ActualT* wireType;
};
static WireType toWireType(T v) {
return new T(v);
static void destroy(WireType) {
}
static Marshaller fromWireType(WireType p) {
return Marshaller(p);
}
static void destroy(WireType p) {
delete p;
}
};
template<typename T>
struct WireDeleter {
typedef typename BindingType<T>::WireType WireType;
WireDeleter(WireType wt)
: wt(wt)
{}
~WireDeleter() {
BindingType<T>::destroy(wt);
}
WireType wt;
};
// catch-all generic binding
@ -219,5 +266,19 @@ namespace emscripten {
return BindingType<T>::toWireType(v);
}
template<typename T>
struct WireDeleter {
typedef typename BindingType<T>::WireType WireType;
WireDeleter(WireType wt)
: wt(wt)
{}
~WireDeleter() {
BindingType<T>::destroy(wt);
}
WireType wt;
};
}
}

Просмотреть файл

@ -1,34 +1,69 @@
#include <emscripten/bind.h>
#ifdef USE_CXA_DEMANGLE
#include <../lib/libcxxabi/include/cxxabi.h>
#endif
#include <list>
#include <vector>
#include <typeinfo>
#include <algorithm>
#include <emscripten/emscripten.h>
#include <climits>
using namespace emscripten;
extern "C" {
const char* __attribute__((used)) __getTypeName(const std::type_info* ti) {
#ifdef USE_CXA_DEMANGLE
int stat;
char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
if (stat == 0 && demangled) {
return demangled;
}
switch (stat) {
case -1:
return strdup("<allocation failure>");
case -2:
return strdup("<invalid C++ symbol>");
case -3:
return strdup("<invalid argument>");
default:
return strdup("<unknown error>");
}
#else
return strdup(ti->name());
#endif
}
}
namespace emscripten {
namespace internal {
void registerStandardTypes() {
static bool first = true;
if (first) {
first = false;
_embind_register_void(getTypeID<void>(), "void");
_embind_register_bool(getTypeID<bool>(), "bool", true, false);
_embind_register_integer(getTypeID<char>(), "char");
_embind_register_integer(getTypeID<signed char>(), "signed char");
_embind_register_integer(getTypeID<unsigned char>(), "unsigned char");
_embind_register_integer(getTypeID<signed short>(), "short");
_embind_register_integer(getTypeID<unsigned short>(), "unsigned short");
_embind_register_integer(getTypeID<signed int>(), "int");
_embind_register_integer(getTypeID<unsigned int>(), "unsigned int");
_embind_register_integer(getTypeID<signed long>(), "long");
_embind_register_integer(getTypeID<unsigned long>(), "unsigned long");
_embind_register_float(getTypeID<float>(), "float");
_embind_register_float(getTypeID<double>(), "double");
_embind_register_cstring(getTypeID<std::string>(), "std::string");
_embind_register_emval(getTypeID<val>(), "emscripten::val");
}
JSInterface* create_js_interface(EM_VAL e) {
return new JSInterface(e);
}
}
}
EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
using namespace emscripten::internal;
_embind_register_void(TypeID<void>::get(), "void");
_embind_register_bool(TypeID<bool>::get(), "bool", true, false);
_embind_register_integer(TypeID<char>::get(), "char", CHAR_MIN, CHAR_MAX);
_embind_register_integer(TypeID<signed char>::get(), "signed char", SCHAR_MIN, SCHAR_MAX);
_embind_register_integer(TypeID<unsigned char>::get(), "unsigned char", 0, UCHAR_MAX);
_embind_register_integer(TypeID<signed short>::get(), "short", SHRT_MIN, SHRT_MAX);
_embind_register_integer(TypeID<unsigned short>::get(), "unsigned short", 0, USHRT_MAX);
_embind_register_integer(TypeID<signed int>::get(), "int", INT_MIN, INT_MAX);
_embind_register_integer(TypeID<unsigned int>::get(), "unsigned int", 0, UINT_MAX);
_embind_register_integer(TypeID<signed long>::get(), "long", LONG_MIN, LONG_MAX);
_embind_register_integer(TypeID<unsigned long>::get(), "unsigned long", 0, ULONG_MAX);
_embind_register_float(TypeID<float>::get(), "float");
_embind_register_float(TypeID<double>::get(), "double");
_embind_register_cstring(TypeID<std::string>::get(), "std::string");
_embind_register_emval(TypeID<val>::get(), "emscripten::val");
}

1587
tests/embind/embind.test.js Executable file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,393 +0,0 @@
//=== testing glue
function module(ignore, func) {
func({ Emscripten: Module });
}
function fixture(name, info) {
Module.print('fixture: ' + name);
for (var test in info) {
var f = info[test];
if (typeof f != 'function') continue;
Module.print('--test: ' + test);
// TODO: Base fixture!
f();
}
}
assert.true = assert;
assert.equal = function(x, y) {
assert(x == y);
}
assert.notEqual = function(x, y) {
assert(x != y);
}
assert.throws = function(exc, func) {
var ret;
try {
func();
} catch(e) {
ret = e;
}
assert(ret); // TODO: check exc vs e
return ret;
}
assert.instanceof = function(inst, clazz) {
assert(inst instanceof clazz);
}
assert.deepEqual = function(x, y) {
assert(JSON.stringify(x) == JSON.stringify(y));
}
//===
module({
Emscripten: '../build/Emscripten.js'
}, function(imports) {
var cm = imports.Emscripten;
var checkForLeaks = {
setUp: function() {
this.originalBlockCount = cm.mallinfo().uordblks;
},
tearDown: function() {
assert.equal(this.originalBlockCount, cm.mallinfo().uordblks);
},
};
fixture("embind", {
baseFixture: checkForLeaks,
"test value creation": function() {
assert.equal(15, cm.emval_test_new_integer());
assert.equal("Hello everyone", cm.emval_test_new_string());
var object = cm.emval_test_new_object();
assert.equal('bar', object.foo);
assert.equal(1, object.baz);
},
"test passthrough": function() {
var a = {foo: 'bar'};
var b = cm.emval_test_passthrough(a);
a.bar = 'baz';
assert.equal('baz', b.bar);
assert.equal(0, cm.count_emval_handles());
},
"test void return converts to undefined": function() {
assert.equal(undefined, cm.emval_test_return_void());
},
"test booleans can be marshalled": function() {
assert.equal(false, cm.emval_test_not(true));
assert.equal(true, cm.emval_test_not(false));
},
"test convert double to unsigned": function() {
var rv = cm.emval_test_as_unsigned(1.5);
assert.equal('number', typeof rv);
assert.equal(1, rv);
assert.equal(0, cm.count_emval_handles());
},
"test get length of array": function() {
assert.equal(10, cm.emval_test_get_length([0, 1, 2, 3, 4, 5, 'a', 'b', 'c', 'd']));
assert.equal(0, cm.count_emval_handles());
},
"test add a bunch of things": function() {
assert.equal(66.0, cm.emval_test_add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
assert.equal(0, cm.count_emval_handles());
},
"test sum array": function() {
assert.equal(66, cm.emval_test_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]));
assert.equal(0, cm.count_emval_handles());
},
"test strings": function() {
assert.equal("foobar", "foo" + "bar");
assert.equal("foobar", cm.emval_test_take_and_return_std_string("foobar"));
assert.equal("foobar", cm.emval_test_take_and_return_std_string_const_ref("foobar"));
},
"test no memory leak when passing strings in by const reference": function() {
var original = cm.mallinfo().uordblks;
cm.emval_test_take_and_return_std_string_const_ref("foobar");
assert.equal(original, cm.mallinfo().uordblks);
},
});
fixture("classes", {
baseFixture: checkForLeaks,
"test class instance": function() {
var a = {foo: 'bar'};
var c = new cm.ValHolder(a);
assert.equal('bar', c.getVal().foo);
c.setVal('1234');
assert.equal('1234', c.getVal());
assert.equal(1239, c.returnIntPlusFive(1234));
c.delete();
assert.equal(0, cm.count_emval_handles());
},
"test class methods": function() {
assert.equal(10, cm.ValHolder.some_class_method(10));
},
"test can't call methods on deleted class instances": function() {
var c = new cm.ValHolder(undefined);
c.delete();
assert.throws(cm.BindingError, function() {
c.getVal();
});
assert.throws(cm.BindingError, function() {
c.delete();
});
},
"test isinstance": function() {
var c = new cm.ValHolder(undefined);
assert.instanceof(c, cm.ValHolder);
c.delete();
},
"test can return class instances by value": function() {
var c = cm.emval_test_return_ValHolder();
assert.deepEqual({}, c.getVal());
c.delete();
},
"test can pass class instances to functions by reference": function() {
var a = {a:1};
var c = new cm.ValHolder(a);
cm.emval_test_set_ValHolder_to_empty_object(c);
assert.deepEqual({}, c.getVal());
c.delete();
},
"test can access struct fields": function() {
var c = new cm.CustomStruct();
assert.equal(10, c.field);
c.delete();
},
"test can set struct fields": function() {
var c = new cm.CustomStruct();
c.field = 15;
assert.equal(15, c.field);
c.delete();
},
"test assignment returns value": function() {
var c = new cm.CustomStruct();
assert.equal(15, c.field = 15);
c.delete();
},
"test assigning string to integer raises TypeError": function() {
var c = new cm.CustomStruct();
var e = assert.throws(TypeError, function() {
c.field = "hi";
});
assert.equal('Cannot convert "hi" to int', e.message);
var e = assert.throws(TypeError, function() {
c.field = {foo:'bar'};
});
assert.equal('Cannot convert "[object Object]" to int', e.message);
c.delete();
},
"test can return tuples by value": function() {
var c = cm.emval_test_return_TupleVector();
assert.deepEqual([1, 2, 3], c);
},
"test tuples can contain tuples": function() {
var c = cm.emval_test_return_TupleVectorTuple();
assert.deepEqual([[1, 2, 3]], c);
},
"test can pass tuples by value": function() {
var c = cm.emval_test_take_and_return_TupleVector([4, 5, 6]);
assert.deepEqual([4, 5, 6], c);
},
"test can return structs by value": function() {
var c = cm.emval_test_return_StructVector();
assert.deepEqual({x: 1, y: 2, z: 3}, c);
},
"test can pass structs by value": function() {
var c = cm.emval_test_take_and_return_StructVector({x: 4, y: 5, z: 6});
assert.deepEqual({x: 4, y: 5, z: 6}, c);
},
"test can pass and return tuples in structs": function() {
var d = cm.emval_test_take_and_return_TupleInStruct({field: [1, 2, 3]});
assert.deepEqual({field: [1, 2, 3]}, d);
},
"test can clone handles": function() {
assert.equal(0, cm.count_emval_handles());
var a = new cm.ValHolder({});
var b = a.clone();
a.delete();
assert.equal(1, cm.count_emval_handles());
assert.throws(cm.BindingError, function() {
a.delete();
});
b.delete();
assert.equal(0, cm.count_emval_handles());
},
"test can't clone if already deleted": function() {
var a = new cm.ValHolder({});
a.delete();
assert.throws(cm.BindingError, function() {
a.clone();
});
},
"test moving handles is a clone+delete": function() {
var a = new cm.ValHolder({});
var b = a.move();
assert.throws(cm.BindingError, function() {
a.delete();
});
assert.equal(1, cm.count_emval_handles());
b.delete();
assert.equal(0, cm.count_emval_handles());
},
"test StringHolder": function() {
var a = new cm.StringHolder("foobar");
assert.equal("foobar", a.get());
a.set("barfoo");
assert.equal("barfoo", a.get());
a.delete();
},
});
fixture("embind enumerations", {
baseFixture: checkForLeaks,
"test can compare enumeration values": function() {
assert.equal(cm.Enum.ONE, cm.Enum.ONE);
assert.notEqual(cm.Enum.ONE, cm.Enum.TWO);
},
"test repr includes enum value": function() {
return; // XXX IMVU?
assert.equal('<#Enum_ONE {}>', IMVU.repr(cm.Enum.ONE));
assert.equal('<#Enum_TWO {}>', IMVU.repr(cm.Enum.TWO));
},
"test instanceof": function() {
assert.instanceof(cm.Enum.ONE, cm.Enum);
},
"test can pass and return enumeration values to functions": function() {
assert.equal(cm.Enum.TWO, cm.emval_test_take_and_return_Enum(cm.Enum.TWO));
},
});
fixture("C++11 enum class", {
baseFixture: checkForLeaks,
"test can compare enumeration values": function() {
assert.equal(cm.EnumClass.ONE, cm.EnumClass.ONE);
assert.notEqual(cm.EnumClass.ONE, cm.EnumClass.TWO);
},
"test repr includes enum value": function() {
return; // XXX IMVU?
assert.equal('<#EnumClass_ONE {}>', IMVU.repr(cm.EnumClass.ONE));
assert.equal('<#EnumClass_TWO {}>', IMVU.repr(cm.EnumClass.TWO));
},
"test instanceof": function() {
assert.instanceof(cm.EnumClass.ONE, cm.EnumClass);
},
"test can pass and return enumeration values to functions": function() {
assert.equal(cm.EnumClass.TWO, cm.emval_test_take_and_return_EnumClass(cm.EnumClass.TWO));
},
});
fixture("emval call tests", {
"test can call functions from C++": function() {
var called = false;
cm.emval_test_call_function(function(i, f, tv, sv) {
called = true;
assert.equal(10, i);
assert.equal(1.5, f);
assert.deepEqual([1.25, 2.5, 3.75], tv);
assert.deepEqual({x: 1.25, y: 2.5, z: 3.75}, sv);
}, 10, 1.5, [1.25, 2.5, 3.75], {x: 1.25, y: 2.5, z: 3.75});
assert.true(called);
},
});
fixture("interfaces", {
baseFixture: checkForLeaks,
"test can wrap JS object in native interface": function() {
var foo = {
calls: [],
method: function() {
this.calls.push('called');
return 10;
}
};
assert.equal(10, cm.emval_test_call_method(foo));
assert.deepEqual(['called'], foo.calls);
},
"test can pass arguments and return complicated values": function() {
var calls = [];
var foo = {
method2: function(arg1, arg2) {
calls.push([arg1, arg2]);
return arg1;
}
};
var result = cm.emval_test_call_method2(foo, {field: [1, 2, 3]}, 7);
assert.deepEqual({field: [1, 2, 3]}, result);
assert.deepEqual([[{field: [1, 2, 3]}, 7]], calls);
},
"test can call interface methods that return nothing": function() {
var calls = [];
var foo = {
method3: function() {
calls.push('called');
}
};
cm.emval_test_call_method3(foo);
assert.deepEqual(['called'], calls);
},
});
});

616
tests/embind/imvu_test_adapter.js Executable file
Просмотреть файл

@ -0,0 +1,616 @@
/* The embind test suite (embind.test.js) is configured to be runnable in two different testing engines:
- The Emscripten python test runner (open-source in emscripten repository) and
- The IMVU test runner (closed-source in IMVU repository)
Embind (and its tests) were originally developed in IMVU repository, which is the reason for two testing architectures.
This adapter file is used when the embind tests are run as part of the Emscripten test runner, to provide the necessary glue code to adapt the tests to Emscripten runner.
To run the Embind tests using the Emscripten test runner, invoke 'python tests/runner.py other.test_embind' in the Emscripten root directory.
*/
/* global Module, console, global, process */
//=== testing glue
function module(ignore, func) {
func({ Emscripten: Module });
}
/*global IMVU:true, TEST_MAX_OUTPUT_SIZE*/
//(function() {
// "use strict";
// { beforeTest: function,
// afterTest: function }
var superFixtures = [];
function registerSuperFixture(superFixture) {
superFixtures.push(superFixture);
}
// { fixture: Fixture instance,
// name: string,
// body: function() }
var allTests = [];
function test(name, fn) {
if (arguments.length !== 2) {
throw new TypeError("test requires 2 arguments");
}
if (undefined !== activeFixture && activeFixture.abstract) {
activeFixture.abstractTests.push({
name: name,
body: fn });
} else {
var fixtureName = (undefined !== activeFixture)? activeFixture.name + ': ' : '';
allTests.push({
name: fixtureName + name,
body: fn,
fixture: activeFixture });
}
}
function runTest(test, continuation) {
try {
var afterTests = [];
for (var i = 0; i < superFixtures.length; ++i) {
var superFixture = superFixtures[i];
var superScope = {};
superFixture.beforeTest.call(superScope);
afterTests.push(superFixture.afterTest.bind(superScope));
}
var testScope = test.fixture ?
Object.create(test.fixture.scope) :
{};
var runSetUp = function(fixtureObject) {
if (undefined === fixtureObject) {
return;
}
runSetUp(fixtureObject.parent);
fixtureObject.setUp.call(testScope);
afterTests.push(fixtureObject.tearDown.bind(testScope));
};
runSetUp(test.fixture);
test.body.call(testScope);
while (afterTests.length) {
afterTests.pop()();
}
return false;
} catch (e) {
console.error('error:', e);
return {stack: e.stack, e: e};
}
}
function run_all(reporter) {
for (var i = 0; i < allTests.length; ++i) {
var test = allTests[i];
reporter({
type: 'test-start',
name: test.name
});
var failed = runTest(test);
if (failed) {
reporter({
type: 'test-complete',
name: test.name,
verdict: 'FAIL',
stack: failed.stack,
e: failed.e
});
return false;
} else {
reporter({
type: 'test-complete',
name: test.name,
verdict: 'PASS'
});
}
}
reporter({
type: 'all-tests-complete'
});
allTests = [];
return true;
}
var activeFixture;
function Fixture(parent, name, definition, abstract_) {
if (!(definition instanceof Function)) {
throw new TypeError("fixture's 2nd argument must be a function");
}
this.name = name;
this.parent = parent;
this.abstract = abstract_;
if (this.abstract) {
// { name: string,
// body: function }
this.abstractTests = [];
}
if (this.parent !== undefined) {
this.parent.addAbstractTests(this);
}
this.scope = (this.parent === undefined ? {} : Object.create(this.parent.scope));
this.scope.setUp = function(setUp) {
this.setUp = setUp;
}.bind(this);
this.scope.tearDown = function(tearDown) {
this.tearDown = tearDown;
}.bind(this);
if (undefined !== activeFixture) {
throw new TypeError("Cannot define a fixture within another fixture");
}
activeFixture = this;
try {
definition.call(this.scope);
}
finally {
activeFixture = undefined;
}
}
Fixture.prototype.setUp = function defaultSetUp() {
};
Fixture.prototype.tearDown = function defaultTearDown() {
};
Fixture.prototype.addAbstractTests = function(concreteFixture) {
if (this.abstract) {
for (var i = 0; i < this.abstractTests.length; ++i) {
var test = this.abstractTests[i];
allTests.push({
name: concreteFixture.name + ': ' + test.name,
body: test.body,
fixture: concreteFixture});
}
}
if (this.parent) {
this.parent.addAbstractTests(concreteFixture);
}
};
Fixture.prototype.extend = function(fixtureName, definition) {
return new Fixture(this, fixtureName, definition, false);
};
function fixture(fixtureName, definition) {
return new Fixture(undefined, fixtureName, definition, false);
}
fixture.abstract = function(fixtureName, definition) {
return new Fixture(undefined, fixtureName, definition, true);
};
var AssertionError = Error;
function fail(exception, info) {
exception.info = info;
throw exception;
}
var formatTestValue = function(v) {
return v.toString();
/*
var s = IMVU.repr(v, TEST_MAX_OUTPUT_SIZE + 1);
if (s.length <= TEST_MAX_OUTPUT_SIZE) {
return s;
}
return s.substring(0, TEST_MAX_OUTPUT_SIZE) + '...';
*/
};
// var assert = {
////////////////////////////////////////////////////////////////////////////////
// GENERAL STATUS
assert.fail = function(info) {
info = info || "assert.fail()";
fail(new AssertionError(info));
},
////////////////////////////////////////////////////////////////////////////////
// BOOLEAN TESTS
assert['true'] = function(value) {
if (!value) {
fail(new AssertionError("expected truthy, actual " + formatTestValue(value)),
{Value: value});
}
},
assert['false'] = function(value) {
if (value) {
fail(new AssertionError("expected falsy, actual " + formatTestValue(value)),
{Value: value});
}
},
////////////////////////////////////////////////////////////////////////////////
// SCALAR COMPARISON
assert.equal = function(expected, actual) {
if (expected !== actual) {
fail(new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual)),
{Expected: expected, Actual: actual});
}
},
assert.notEqual = function(expected, actual) {
if (expected === actual) {
fail(new AssertionError('actual was equal to: ' + formatTestValue(expected)));
}
},
assert.greater = function(lhs, rhs) {
if (lhs <= rhs) {
fail(new AssertionError(formatTestValue(lhs) + ' not greater than ' + formatTestValue(rhs)));
}
},
assert.less = function(lhs, rhs) {
if (lhs >= rhs) {
fail(new AssertionError(formatTestValue(lhs) + ' not less than ' + formatTestValue(rhs)));
}
},
assert.greaterOrEqual = function(lhs, rhs) {
if (lhs < rhs) {
fail(new AssertionError(formatTestValue(lhs) + ' not greater than or equal to ' + formatTestValue(rhs)));
}
},
assert.lessOrEqual = function(lhs, rhs) {
if (lhs > rhs) {
fail(new AssertionError(formatTestValue(lhs) + ' not less than or equal to ' + formatTestValue(rhs)));
}
},
////////////////////////////////////////////////////////////////////////////////
// DEEP COMPARISON
assert.deepEqual = function(expected, actual) {
if (!_.isEqual(expected, actual)) {
fail(new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual)),
{Expected: expected, Actual: actual});
}
},
assert.notDeepEqual = function(expected, actual) {
if (_.isEqual(expected, actual)) {
fail(new AssertionError('expected: ' + formatTestValue(expected) + ' and actual: ' + formatTestValue(actual) + ' were equal'));
}
},
////////////////////////////////////////////////////////////////////////////////
// FLOATING POINT
assert.nearEqual = function( expected, actual, tolerance ) {
if( tolerance === undefined ) {
tolerance = 0.0;
}
if( expected instanceof Array && actual instanceof Array ) {
assert.equal(expected.length, actual.length);
for( var i=0; i<expected.length; ++i ) {
assert.nearEqual(expected[i], actual[i], tolerance);
}
return;
}
if( Math.abs(expected - actual) > tolerance ) {
fail( new AssertionError('expected: ' + formatTestValue(expected) + ', actual: ' + formatTestValue(actual) +
', tolerance: ' + formatTestValue(tolerance) + ', diff: ' + formatTestValue(actual-expected) ),
{ Expected:expected, Actual:actual, Tolerance:tolerance } );
}
},
////////////////////////////////////////////////////////////////////////////////
// STRING
assert.inString = function(expected, string){
if (-1 === string.indexOf(expected)){
fail(new AssertionError('expected: ' + formatTestValue(expected) + ' not in string: ' + formatTestValue(string)),
{Expected: expected, 'String': string});
}
},
assert.notInString = function(expected, string){
if (-1 !== string.indexOf(expected)){
fail(new AssertionError('unexpected: ' + formatTestValue(expected) + ' in string: ' + formatTestValue(string)),
{Expected: expected, 'String': string});
}
},
assert.matches = function(re, string) {
if (!re.test(string)) {
fail(new AssertionError('regexp ' + re + ' does not match: ' + string));
}
},
////////////////////////////////////////////////////////////////////////////////
// ARRAY
assert.inArray = function(expected, array) {
var found = false;
_.each(array, function(element){
if (_.isEqual(expected, element)){
found = true;
}
});
if (!found){
fail(new AssertionError('expected: ' + formatTestValue(expected) + ' not found in array: ' + formatTestValue(array)),
{Expected: expected, 'Array': array});
}
},
assert.notInArray = function(expected, array) {
var found = false;
_.each(array, function(element){
if (_.isEqual(expected, element)){
found = true;
}
});
if (found){
fail(new AssertionError('unexpected: ' + formatTestValue(expected) + ' found in array: ' + formatTestValue(array)),
{Expected: expected, 'Array': array});
}
},
////////////////////////////////////////////////////////////////////////////////
// OBJECTS
assert.hasKey = function (key, object) {
if (!(key in object)) {
fail(new AssertionError('Key ' + formatTestValue(key) + ' is not in object: ' + formatTestValue(object)));
}
},
assert.notHasKey = function (key, object) {
if (key in object) {
fail(new AssertionError('Unexpected key ' + formatTestValue(key) + ' is found in object: ' + formatTestValue(object)));
}
},
////////////////////////////////////////////////////////////////////////////////
// EXCEPTIONS
assert.throws = function(exception, fn) {
try {
fn();
} catch (e) {
if (e instanceof exception) {
return e;
}
fail(new AssertionError('Expected to throw "' + exception.name + '", actually threw: ' + formatTestValue(e) + ': ' + e.message),
{Expected: exception, Actual: e});
}
throw new AssertionError('did not throw');
},
////////////////////////////////////////////////////////////////////////////////
// TYPE
assert['instanceof'] = function(actual, type) {
if(!(actual instanceof type)) {
fail(new AssertionError(formatTestValue(actual) + ' not instance of ' + formatTestValue(type)),
{Type: type, Actual: actual});
}
},
////////////////////////////////////////////////////////////////////////////////
// DOM ASSERTIONS
// TODO: lift into separate file?
assert.dom = {
present: function(domElement){
if (!$(domElement).length) {
fail(new AssertionError(decipherDomElement(domElement) + ' should be present'));
}
},
notPresent: function(selector){
assert.equal(0, $(selector).length);
},
hasTag: function(tag, domElement) {
var elementTag = $(domElement)[0].tagName.toLowerCase();
if (elementTag !== tag.toLowerCase()) {
fail(new AssertionError(decipherDomElement(domElement) + ' expected to have tag name ' + formatTestValue(tag) + ', was ' + formatTestValue(elementTag) + ' instead'));
}
},
hasClass: function(className, domElement) {
if (!$(domElement).hasClass(className)){
fail(new AssertionError(decipherDomElement(domElement) + ' expected to have class '+ formatTestValue(className) + ', has ' + formatTestValue($(domElement).attr('class')) + ' instead'));
}
},
notHasClass: function(className, domElement) {
assert.dom.present(domElement); // if domElement is empty, .hasClass will always return false
if ($(domElement).hasClass(className)){
fail(new AssertionError(decipherDomElement(domElement) + ' expected NOT to have class '+ formatTestValue(className)));
}
},
hasAttribute: function(attributeName, selector) {
assert['true']($(selector).is('[' + attributeName + ']'));
},
notHasAttribute: function(attributeName, selector) {
assert.dom.present(selector);
assert['false']($(selector).is('[' + attributeName + ']'));
},
attr: function(value, attributeName, selector) {
assert.equal(value, $(selector).attr(attributeName));
},
attributeValues: function (values, selector) {
var $el = $(selector);
_(values).each(function (val, key) {
assert.equal(val, $el.attr(key));
});
},
text: function(expected, selector) {
assert.equal(expected, $(selector).text());
},
value: function(expected, selector) {
assert.equal(expected, $(selector).val());
},
count: function(elementCount, selector) {
assert.equal(elementCount, $(selector).length);
},
visible: function(domElement) {
if (!$(domElement).is(':visible')) {
fail(new AssertionError(decipherDomElement(domElement) + ' expected to be visible'));
}
},
notVisible: function(domElement) {
assert.dom.present(domElement);
if ($(domElement).is(':visible')) {
fail(new AssertionError(decipherDomElement(domElement) + ' expected to be NOT visible'));
}
},
disabled: function(domElement) {
if (!$(domElement).is(':disabled')) {
fail(new AssertionError(decipherDomElement(domElement) + ' expected to be disabled'));
}
},
enabled: function(domElement) {
if (!$(domElement).is(':enabled')) {
fail(new AssertionError(decipherDomElement(domElement) + ' expected to be enabled'));
}
},
focused: function(selector) {
var expected = $(selector)[0];
var actual = document.activeElement;
if (expected !== actual) {
throw new AssertionError(actual.outerHTML + ' has focus. expected: ' + expected.outerHTML);
}
},
notFocused: function(selector) {
var expected = $(selector)[0];
var actual = document.activeElement;
if (expected === actual) {
throw new AssertionError(expected.outerHTML + ' expected not to have focus.');
}
},
html: function(expected, selector) {
assert.equal(expected, $(selector).html());
},
css: function(expected, propertyName, selector) {
assert.equal(expected, $(selector).css(propertyName));
},
empty: function(selectorOrJQueryObject) {
var el = selectorOrJQueryObject;
assert.dom.present(el);
if (!$(el).is(':empty')) {
fail(new AssertionError(decipherDomElement(el) + ' expected to be empty'));
}
},
notEmpty: function(selectorOrJQueryObject) {
var el = selectorOrJQueryObject;
assert.dom.present(el);
if ($(el).is(':empty')) {
fail(new AssertionError(decipherDomElement(el) + ' expected NOT to be empty'));
}
}
};
// };
function decipherDomElement(selectorOrJQueryObject) {
if (typeof selectorOrJQueryObject === 'string') {
return 'Selector ' + formatTestValue(selectorOrJQueryObject);
} else if (typeof selectorOrJQueryObject === 'object') {
return "'" + selectorOrJQueryObject[0] + "'";
}
}
var g = 'undefined' === typeof window ? global : window;
// synonyms
assert.equals = assert.equal;
assert.notEquals = assert.notEqual;
assert['null'] = assert.equal.bind(null, null);
assert.notNull = assert.notEqual.bind(null, null);
assert['undefined'] = assert.equal.bind(null, undefined);
assert.notUndefined = assert.notEqual.bind(null, undefined);
// ES3 synonyms
assert.false_ = assert['false'];
assert.true_ = assert['true'];
g.registerSuperFixture = registerSuperFixture;
g.test = test;
g.run_all = run_all;
g.fixture = fixture;
// g.repr = IMVU.repr;
g.AssertionError = AssertionError;
g.assert = assert;
g.test = test;
g.TEST_MAX_OUTPUT_SIZE = 1024;
g.setTimeout = function(fn, time) {
if (time === 1 || time === 0){
fn();
return 0;
}
throw new AssertionError("Don't call setTimeout in tests. Use fakes.");
};
g.setInterval = function() {
throw new AssertionError("Don't call setInterval in tests. Use fakes.");
};
if (typeof process !== 'undefined') {
process.nextTick = function() {
throw new AssertionError("Don't call process.nextTick in tests. Use fakes.");
};
}
Math.random = function() {
throw new AssertionError("Don't call Math.random in tests. Use fakes.");
};
g.requestAnimationFrame = function() {
throw new AssertionError("Don't call requestAnimationFrame in tests. Use fakes.");
};
//})();
// Emscripten runner starts all tests from this function.
// IMVU runner uses a separate runner & reporting mechanism.
function run_all_tests() {
function report_to_stdout(msg) {
if (msg.type === "test-complete")
console.log(msg.name + ": " + msg.verdict);
}
run_all(report_to_stdout);
}
// Signal the embind test suite that it is being run from the Emscripten python test runner and not the
// IMVU test runner.
var INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER = 1;

1200
tests/embind/underscore-1.4.2.js Executable file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -10247,58 +10247,12 @@ f.close()
print args, fail
self.clear()
try_delete(self.in_dir('a.out.js'))
Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'embind_test.js')] + args, stderr=PIPE if fail else None).communicate()
Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate()
assert os.path.exists(self.in_dir('a.out.js')) == (not fail)
if not fail:
output = run_js(self.in_dir('a.out.js'))
self.assertContained('''fixture: embind
--test: test value creation
--test: test passthrough
--test: test void return converts to undefined
--test: test booleans can be marshalled
--test: test convert double to unsigned
--test: test get length of array
--test: test add a bunch of things
--test: test sum array
--test: test strings
--test: test no memory leak when passing strings in by const reference
fixture: classes
--test: test class instance
--test: test class methods
--test: test can't call methods on deleted class instances
--test: test isinstance
--test: test can return class instances by value
--test: test can pass class instances to functions by reference
--test: test can access struct fields
--test: test can set struct fields
--test: test assignment returns value
--test: test assigning string to integer raises TypeError
--test: test can return tuples by value
--test: test tuples can contain tuples
--test: test can pass tuples by value
--test: test can return structs by value
--test: test can pass structs by value
--test: test can pass and return tuples in structs
--test: test can clone handles
--test: test can't clone if already deleted
--test: test moving handles is a clone+delete
--test: test StringHolder
fixture: embind enumerations
--test: test can compare enumeration values
--test: test repr includes enum value
--test: test instanceof
--test: test can pass and return enumeration values to functions
fixture: C++11 enum class
--test: test can compare enumeration values
--test: test repr includes enum value
--test: test instanceof
--test: test can pass and return enumeration values to functions
fixture: emval call tests
--test: test can call functions from C++
fixture: interfaces
--test: test can wrap JS object in native interface
--test: test can pass arguments and return complicated values
--test: test can call interface methods that return nothing''', output)
output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True)
print >> sys.stderr, output
assert "FAIL" not in output
def test_llvm_nativizer(self):
try: