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#include <wtf/Assertions.h>
34
35// Helper classes for implementing has_member
36typedef char (&no_tag)[1];
37typedef char (&yes_tag)[2];
38
39#define DEFINE_HAS_MEMBER_CHECK(member, returnType, argumentTypes) \
40template<typename T, returnType (T::*member) argumentTypes> struct pmf_##member##_helper {}; \
41template<typename T> no_tag has_member_##member##_helper(...); \
42template<typename T> yes_tag has_member_##member##_helper(pmf_##member##_helper<T, &T::member >*); \
43template<typename T> struct has_member_##member { \
44static const bool value = sizeof(has_member_##member##_helper<T>(0)) == sizeof(yes_tag); \
45};
46
47DEFINE_HAS_MEMBER_CHECK(hasMethod, bool, (NPIdentifier methodName));
48DEFINE_HAS_MEMBER_CHECK(invoke, bool, (NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result));
49DEFINE_HAS_MEMBER_CHECK(invokeDefault, bool, (const NPVariant*, uint32_t, NPVariant* result));
50DEFINE_HAS_MEMBER_CHECK(hasProperty, bool, (NPIdentifier propertyName));
51DEFINE_HAS_MEMBER_CHECK(getProperty, bool, (NPIdentifier propertyName, NPVariant* result));
52DEFINE_HAS_MEMBER_CHECK(removeProperty, bool, (NPIdentifier propertyName));
53
54class PluginTest {
55public:
56 static PluginTest* create(NPP, const std::string& identifier);
57 virtual ~PluginTest();
58
59 static void NP_Shutdown();
60
61 // NPP functions.
62 virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved);
63 virtual NPError NPP_Destroy(NPSavedData**);
64 virtual NPError NPP_SetWindow(NPWindow*);
65 virtual NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
66 virtual NPError NPP_DestroyStream(NPStream*, NPReason);
67 virtual int32_t NPP_WriteReady(NPStream*);
68 virtual int32_t NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer);
69
70 virtual int16_t NPP_HandleEvent(void* event);
71 virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData);
72 virtual void NPP_URLRedirectNotify(const char* url, int32_t status, void* notifyData);
73 virtual NPError NPP_GetValue(NPPVariable, void* value);
74 virtual NPError NPP_SetValue(NPNVariable, void *value);
75
76 // NPN functions.
77 NPError NPN_GetURL(const char* url, const char* target);
78 NPError NPN_GetURLNotify(const char* url, const char* target, void* notifyData);
79 NPError NPN_PostURLNotify(const char *url, const char *target, uint32_t len, const char* buf, NPBool file, void *notifyData);
80 NPError NPN_GetValue(NPNVariable, void* value);
81 void NPN_InvalidateRect(NPRect* invalidRect);
82 bool NPN_Invoke(NPObject *, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
83 void* NPN_MemAlloc(uint32_t size);
84
85 // NPRuntime NPN functions.
86 NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
87 NPIdentifier NPN_GetIntIdentifier(int32_t intid);
88 bool NPN_IdentifierIsString(NPIdentifier);
89 NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier);
90 int32_t NPN_IntFromIdentifier(NPIdentifier);
91
92 NPObject* NPN_CreateObject(NPClass*);
93 NPObject* NPN_RetainObject(NPObject*);
94 void NPN_ReleaseObject(NPObject*);
95 bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
96 void NPN_ReleaseVariantValue(NPVariant*);
97 void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
98
99#ifdef XP_MACOSX
100 bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
101#endif
102
103 bool executeScript(const NPString*, NPVariant* result);
104 void executeScript(const char*);
105 void log(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
106
107 void registerNPShutdownFunction(void (*)());
108
109 static void indicateTestFailure();
110
111 template<typename TestClassTy> class Register {
112 public:
113 Register(const std::string& identifier)
114 {
115 registerCreateTestFunction(identifier, Register::create);
116 }
117
118 private:
119 static PluginTest* create(NPP npp, const std::string& identifier)
120 {
121 return new TestClassTy(npp, identifier);
122 }
123 };
124
125protected:
126 PluginTest(NPP npp, const std::string& identifier);
127
128 // FIXME: A plug-in test shouldn't need to know about it's NPP. Make this private.
129 NPP m_npp;
130
131 const std::string& identifier() const { return m_identifier; }
132
133 static NPNetscapeFuncs* netscapeFuncs();
134
135 void waitUntilDone();
136 void notifyDone();
137
138 // NPObject helper template.
139 template<typename T> struct Object : NPObject {
140 public:
141 static NPObject* create(PluginTest* pluginTest)
142 {
143 Object* object = static_cast<Object*>(pluginTest->NPN_CreateObject(npClass()));
144
145 object->m_pluginTest = pluginTest;
146 return object;
147 }
148
149 // These should never be called.
150 bool hasMethod(NPIdentifier methodName)
151 {
152 assert(false);
153 return false;
154 }
155
156 bool invoke(NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result)
157 {
158 assert(false);
159 return false;
160 }
161
162 bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result)
163 {
164 assert(false);
165 return false;
166 }
167
168 bool hasProperty(NPIdentifier propertyName)
169 {
170 assert(false);
171 return false;
172 }
173
174 bool getProperty(NPIdentifier propertyName, NPVariant* result)
175 {
176 assert(false);
177 return false;
178 }
179
180 bool removeProperty(NPIdentifier propertyName)
181 {
182 assert(false);
183 return false;
184 }
185
186 // Helper functions.
187 bool identifierIs(NPIdentifier identifier, const char* value)
188 {
189 return pluginTest()->NPN_GetStringIdentifier(value) == identifier;
190 }
191
192 protected:
193 Object()
194 : m_pluginTest(0)
195 {
196 }
197
198 virtual ~Object()
199 {
200 }
201
202 PluginTest* pluginTest() const { return m_pluginTest; }
203
204 private:
205 static NPObject* NP_Allocate(NPP npp, NPClass* aClass)
206 {
207 return new T;
208 }
209
210 static void NP_Deallocate(NPObject* npObject)
211 {
212 delete static_cast<T*>(npObject);
213 }
214
215 static bool NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
216 {
217 return static_cast<T*>(npObject)->hasMethod(methodName);
218 }
219
220 static bool NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
221 {
222 return static_cast<T*>(npObject)->invoke(methodName, arguments, argumentCount, result);
223 }
224
225 static bool NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
226 {
227 return static_cast<T*>(npObject)->invokeDefault(arguments, argumentCount, result);
228 }
229
230 static bool NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
231 {
232 return static_cast<T*>(npObject)->hasProperty(propertyName);
233 }
234
235 static bool NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
236 {
237 return static_cast<T*>(npObject)->getProperty(propertyName, result);
238 }
239
240 static bool NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
241 {
242 return static_cast<T*>(npObject)->removeProperty(propertyName);
243 }
244
245 static NPClass* npClass()
246 {
247 static NPClass npClass = {
248 NP_CLASS_STRUCT_VERSION,
249 NP_Allocate,
250 NP_Deallocate,
251 0, // NPClass::invalidate
252 has_member_hasMethod<T>::value ? NP_HasMethod : 0,
253 has_member_invoke<T>::value ? NP_Invoke : 0,
254 has_member_invokeDefault<T>::value ? NP_InvokeDefault : 0,
255 has_member_hasProperty<T>::value ? NP_HasProperty : 0,
256 has_member_getProperty<T>::value ? NP_GetProperty : 0,
257 0, // NPClass::setProperty
258 has_member_removeProperty<T>::value ? NP_RemoveProperty : 0,
259 0, // NPClass::enumerate
260 0 // NPClass::construct
261 };
262
263 return &npClass;
264 };
265
266 PluginTest* m_pluginTest;
267 };
268
269private:
270 typedef PluginTest* (*CreateTestFunction)(NPP, const std::string&);
271
272 static void registerCreateTestFunction(const std::string&, CreateTestFunction);
273 static std::map<std::string, CreateTestFunction>& createTestFunctions();
274
275 std::string m_identifier;
276};
277
278#endif // PluginTest_h
279