1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef PluginTest_h
27#define PluginTest_h
28
29#include <assert.h>
30#include <bindings/npfunctions.h>
31#include <map>
32#include <string>
33
34// Helper classes for implementing has_member
35typedef char (&no_tag)[1];
36typedef char (&yes_tag)[2];
37
38#define DEFINE_HAS_MEMBER_CHECK(member, returnType, argumentTypes) \
39template<typename T, returnType (T::*member) argumentTypes> struct pmf_##member##_helper {}; \
40template<typename T> no_tag has_member_##member##_helper(...); \
41template<typename T> yes_tag has_member_##member##_helper(pmf_##member##_helper<T, &T::member >*); \
42template<typename T> struct has_member_##member { \
43static const bool value = sizeof(has_member_##member##_helper<T>(0)) == sizeof(yes_tag); \
44};
45
46DEFINE_HAS_MEMBER_CHECK(hasMethod, bool, (NPIdentifier methodName));
47DEFINE_HAS_MEMBER_CHECK(invoke, bool, (NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result));
48DEFINE_HAS_MEMBER_CHECK(invokeDefault, bool, (const NPVariant*, uint32_t, NPVariant* result));
49DEFINE_HAS_MEMBER_CHECK(hasProperty, bool, (NPIdentifier propertyName));
50DEFINE_HAS_MEMBER_CHECK(getProperty, bool, (NPIdentifier propertyName, NPVariant* result));
51DEFINE_HAS_MEMBER_CHECK(removeProperty, bool, (NPIdentifier propertyName));
52
53class PluginTest {
54public:
55    static PluginTest* create(NPP, const std::string& identifier);
56    virtual ~PluginTest();
57
58    static void NP_Shutdown();
59
60    // NPP functions.
61    virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved);
62    virtual NPError NPP_Destroy(NPSavedData**);
63    virtual NPError NPP_SetWindow(NPWindow*);
64    virtual NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
65    virtual NPError NPP_DestroyStream(NPStream*, NPReason);
66    virtual int32_t NPP_WriteReady(NPStream*);
67    virtual int32_t NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer);
68    virtual int16_t NPP_HandleEvent(void* event);
69    virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData);
70    virtual NPError NPP_GetValue(NPPVariable, void* value);
71    virtual NPError NPP_SetValue(NPNVariable, void *value);
72
73    // NPN functions.
74    NPError NPN_GetURL(const char* url, const char* target);
75    NPError NPN_GetURLNotify(const char* url, const char* target, void* notifyData);
76    NPError NPN_GetValue(NPNVariable, void* value);
77    void NPN_InvalidateRect(NPRect* invalidRect);
78    bool NPN_Invoke(NPObject *, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
79    void* NPN_MemAlloc(uint32_t size);
80
81    // NPRuntime NPN functions.
82    NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
83    NPIdentifier NPN_GetIntIdentifier(int32_t intid);
84    bool NPN_IdentifierIsString(NPIdentifier);
85    NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier);
86    int32_t NPN_IntFromIdentifier(NPIdentifier);
87
88    NPObject* NPN_CreateObject(NPClass*);
89    NPObject* NPN_RetainObject(NPObject*);
90    void NPN_ReleaseObject(NPObject*);
91    bool NPN_GetProperty(NPObject*, NPIdentifier propertyName, NPVariant* value);
92    bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
93    void NPN_ReleaseVariantValue(NPVariant*);
94
95#ifdef XP_MACOSX
96    bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
97#endif
98
99    bool executeScript(const NPString*, NPVariant* result);
100    void executeScript(const char*);
101    void log(const char* format, ...);
102
103    void registerNPShutdownFunction(void (*)());
104
105    static void indicateTestFailure();
106
107    template<typename TestClassTy> class Register {
108    public:
109        Register(const std::string& identifier)
110        {
111            registerCreateTestFunction(identifier, Register::create);
112        }
113
114    private:
115        static PluginTest* create(NPP npp, const std::string& identifier)
116        {
117            return new TestClassTy(npp, identifier);
118        }
119    };
120
121protected:
122    PluginTest(NPP npp, const std::string& identifier);
123
124    // FIXME: A plug-in test shouldn't need to know about it's NPP. Make this private.
125    NPP m_npp;
126
127    const std::string& identifier() const { return m_identifier; }
128
129    static NPNetscapeFuncs* netscapeFuncs();
130
131    void waitUntilDone();
132    void notifyDone();
133
134    // NPObject helper template.
135    template<typename T> struct Object : NPObject {
136    public:
137        static NPObject* create(PluginTest* pluginTest)
138        {
139            Object* object = static_cast<Object*>(pluginTest->NPN_CreateObject(npClass()));
140
141            object->m_pluginTest = pluginTest;
142            return object;
143        }
144
145        // These should never be called.
146        bool hasMethod(NPIdentifier methodName)
147        {
148            assert(false);
149            return false;
150        }
151
152        bool invoke(NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result)
153        {
154            assert(false);
155            return false;
156        }
157
158        bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result)
159        {
160            assert(false);
161            return false;
162        }
163
164        bool hasProperty(NPIdentifier propertyName)
165        {
166            assert(false);
167            return false;
168        }
169
170        bool getProperty(NPIdentifier propertyName, NPVariant* result)
171        {
172            assert(false);
173            return false;
174        }
175
176        bool removeProperty(NPIdentifier propertyName)
177        {
178            assert(false);
179            return false;
180        }
181
182        // Helper functions.
183        bool identifierIs(NPIdentifier identifier, const char* value)
184        {
185            return pluginTest()->NPN_GetStringIdentifier(value) == identifier;
186        }
187
188    protected:
189        Object()
190            : m_pluginTest(0)
191        {
192        }
193
194        virtual ~Object()
195        {
196        }
197
198        PluginTest* pluginTest() const { return m_pluginTest; }
199
200    private:
201        static NPObject* NP_Allocate(NPP npp, NPClass* aClass)
202        {
203            return new T;
204        }
205
206        static void NP_Deallocate(NPObject* npObject)
207        {
208            delete static_cast<T*>(npObject);
209        }
210
211        static bool NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
212        {
213            return static_cast<T*>(npObject)->hasMethod(methodName);
214        }
215
216        static bool NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
217        {
218            return static_cast<T*>(npObject)->invoke(methodName, arguments, argumentCount, result);
219        }
220
221        static bool NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
222        {
223            return static_cast<T*>(npObject)->invokeDefault(arguments, argumentCount, result);
224        }
225
226        static bool NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
227        {
228            return static_cast<T*>(npObject)->hasProperty(propertyName);
229        }
230
231        static bool NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
232        {
233            return static_cast<T*>(npObject)->getProperty(propertyName, result);
234        }
235
236        static bool NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
237        {
238            return static_cast<T*>(npObject)->removeProperty(propertyName);
239        }
240
241        static NPClass* npClass()
242        {
243            static NPClass npClass = {
244                NP_CLASS_STRUCT_VERSION,
245                NP_Allocate,
246                NP_Deallocate,
247                0, // NPClass::invalidate
248                has_member_hasMethod<T>::value ? NP_HasMethod : 0,
249                has_member_invoke<T>::value ? NP_Invoke : 0,
250                has_member_invokeDefault<T>::value ? NP_InvokeDefault : 0,
251                has_member_hasProperty<T>::value ? NP_HasProperty : 0,
252                has_member_getProperty<T>::value ? NP_GetProperty : 0,
253                0, // NPClass::setProperty
254                has_member_removeProperty<T>::value ? NP_RemoveProperty : 0,
255                0, // NPClass::enumerate
256                0  // NPClass::construct
257            };
258
259            return &npClass;
260        };
261
262        PluginTest* m_pluginTest;
263    };
264
265private:
266    typedef PluginTest* (*CreateTestFunction)(NPP, const std::string&);
267
268    static void registerCreateTestFunction(const std::string&, CreateTestFunction);
269    static std::map<std::string, CreateTestFunction>& createTestFunctions();
270
271    std::string m_identifier;
272};
273
274#endif // PluginTest_h
275