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 <WebKit/npfunctions.h>
30#include <assert.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));
51
52class PluginTest {
53public:
54    static PluginTest* create(NPP, const std::string& identifier);
55    virtual ~PluginTest();
56
57    static void NP_Shutdown();
58
59    // NPP functions.
60    virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved);
61    virtual NPError NPP_Destroy(NPSavedData**);
62    virtual NPError NPP_DestroyStream(NPStream* stream, NPReason reason);
63    virtual NPError NPP_GetValue(NPPVariable, void* value);
64    virtual NPError NPP_SetWindow(NPP, NPWindow*);
65    virtual int16_t NPP_HandleEvent(void* event);
66
67    // NPN functions.
68    NPError NPN_GetURL(const char* url, const char* target);
69
70    void NPN_InvalidateRect(NPRect* invalidRect);
71    NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
72    NPIdentifier NPN_GetIntIdentifier(int32_t intid);
73    NPError NPN_GetValue(NPNVariable, void* value);
74    NPObject* NPN_CreateObject(NPClass*);
75    bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
76#ifdef XP_MACOSX
77    bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
78#endif
79
80    void executeScript(const char*);
81    void log(const char* format, ...);
82
83    void registerNPShutdownFunction(void (*)());
84
85    static void indicateTestFailure();
86
87    template<typename TestClassTy> class Register {
88    public:
89        Register(const std::string& identifier)
90        {
91            registerCreateTestFunction(identifier, Register::create);
92        }
93
94    private:
95        static PluginTest* create(NPP npp, const std::string& identifier)
96        {
97            return new TestClassTy(npp, identifier);
98        }
99    };
100
101protected:
102    PluginTest(NPP npp, const std::string& identifier);
103
104    // FIXME: A plug-in test shouldn't need to know about it's NPP. Make this private.
105    NPP m_npp;
106
107    const std::string& identifier() const { return m_identifier; }
108
109    void waitUntilDone();
110    void notifyDone();
111
112    // NPObject helper template.
113    template<typename T> struct Object : NPObject {
114    public:
115        static NPObject* create(PluginTest* pluginTest)
116        {
117            Object* object = static_cast<Object*>(pluginTest->NPN_CreateObject(npClass()));
118
119            object->m_pluginTest = pluginTest;
120            return object;
121        }
122
123        // These should never be called.
124        bool hasMethod(NPIdentifier methodName)
125        {
126            assert(false);
127            return false;
128        }
129
130        bool invoke(NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result)
131        {
132            assert(false);
133            return false;
134        }
135
136        bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result)
137        {
138            assert(false);
139            return false;
140        }
141
142        bool hasProperty(NPIdentifier propertyName)
143        {
144            assert(false);
145            return false;
146        }
147
148        bool getProperty(NPIdentifier propertyName, NPVariant* result)
149        {
150            assert(false);
151            return false;
152        }
153
154    protected:
155        Object()
156            : m_pluginTest(0)
157        {
158        }
159
160        virtual ~Object()
161        {
162        }
163
164        PluginTest* pluginTest() const { return m_pluginTest; }
165
166    private:
167        static NPObject* NP_Allocate(NPP npp, NPClass* aClass)
168        {
169            return new T;
170        }
171
172        static void NP_Deallocate(NPObject* npObject)
173        {
174            delete static_cast<T*>(npObject);
175        }
176
177        static bool NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
178        {
179            return static_cast<T*>(npObject)->hasMethod(methodName);
180        }
181
182        static bool NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
183        {
184            return static_cast<T*>(npObject)->invoke(methodName, arguments, argumentCount, result);
185        }
186
187        static bool NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
188        {
189            return static_cast<T*>(npObject)->invokeDefault(arguments, argumentCount, result);
190        }
191
192        static bool NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
193        {
194            return static_cast<T*>(npObject)->hasProperty(propertyName);
195        }
196
197        static bool NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
198        {
199            return static_cast<T*>(npObject)->getProperty(propertyName, result);
200        }
201
202        static NPClass* npClass()
203        {
204            static NPClass npClass = {
205                NP_CLASS_STRUCT_VERSION,
206                NP_Allocate,
207                NP_Deallocate,
208                0, // NPClass::invalidate
209                has_member_hasMethod<T>::value ? NP_HasMethod : 0,
210                has_member_invoke<T>::value ? NP_Invoke : 0,
211                has_member_invokeDefault<T>::value ? NP_InvokeDefault : 0,
212                has_member_hasProperty<T>::value ? NP_HasProperty : 0,
213                has_member_getProperty<T>::value ? NP_GetProperty : 0,
214                0, // NPClass::setProperty
215                0, // NPClass::removeProperty
216                0, // NPClass::enumerate
217                0  // NPClass::construct
218            };
219
220            return &npClass;
221        };
222
223        PluginTest* m_pluginTest;
224    };
225
226private:
227    typedef PluginTest* (*CreateTestFunction)(NPP, const std::string&);
228
229    static void registerCreateTestFunction(const std::string&, CreateTestFunction);
230    static std::map<std::string, CreateTestFunction>& createTestFunctions();
231
232    std::string m_identifier;
233};
234
235#endif // PluginTest_h
236