Commit ae094af7 authored by aroben@apple.com's avatar aroben@apple.com

Pass NPP_SetWindow a null window handle during plugin destruction on non-Mac platforms

This matches WebKit1.

Fixes <http://webkit.org/b/47009> WebKit2 needs to call NPP_SetWindow when destroying a
plugin

Reviewed by Anders Carlsson.

Source/WebKit2:

* WebProcess/Plugins/Netscape/NetscapePlugin.cpp:
(WebKit::NetscapePlugin::destroy): Null out our NPWindow's window handle and pass it to
NPP_SetWindow (unless we're on Mac).

Tools:

Test that NPP_SetWindow is passed a null window handle during plugin destruction on non-Mac platforms

* DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
(pluginLogWithArguments): Moved code to format and log the message here...
(pluginLog): ...from here.

* DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Added pluginLogWithArguments.

* DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
(PluginTest::log): Added. Calls through to pluginLogWithArguments.

* DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added log.

* DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp: Added.
(NPPSetWindowCalledDuringDestruction::setWillBeDestroyed): Records that destruction is about
to begin.
(NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction): Simple
constructor.
(NPPSetWindowCalledDuringDestruction::NPP_GetValue): Creates and returns a ScriptObject that
can be used to invoke our setWillBeDestroyed function.
(NPPSetWindowCalledDuringDestruction::NPP_SetWindow): Records what has happened (and logs if
anything unexpected happens).
(NPPSetWindowCalledDuringDestruction::NPP_Destroy): On Mac, logs a failure message if
NPP_SetWindow was called during destruction. On other platforms, logs a failure message if
NPP_SetWindow was *not* called during destruction.
(NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod): Return true for our only
method, setWillBeDestroyed.
(NPPSetWindowCalledDuringDestruction::ScriptObject::invoke): Call through to the PluginTest
object.

* DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
* DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
* DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
* GNUmakefile.am:
Added new test.

* Scripts/old-run-webkit-tests: Skip the new test when using out-of-process plugins with
WebKit1 on Mac, since it can't work properly due to <http://webkit.org/b/58077>.

LayoutTests:

Test that NPP_SetWindow is passed a null window handle during plugin destruction on non-Mac platforms

* platform/win-wk2/Skipped: Removed a test that no longer crashes thanks to this fix.

* plugins/npp-set-window-called-during-destruction-expected.txt: Added.
* plugins/npp-set-window-called-during-destruction.html: Added.

* platform/mac/plugins/npp-set-window-called-during-destruction-expected.txt: Added. This is
different from the cross-platform results because we don't expect NPP_SetWindow to be called
during destruction.

* platform/win/plugins/npp-set-window-called-during-destruction-expected.txt: Added. This is
a copy of the cross-platform results, needed to override the Mac-specific results.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@83300 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 89007679
2011-04-07 Adam Roben <aroben@apple.com>
Test that NPP_SetWindow is passed a null window handle during plugin destruction on non-Mac platforms
Test for <http://webkit.org/b/47009> WebKit2 needs to call NPP_SetWindow when destroying a
plugin
Reviewed by Anders Carlsson.
* platform/win-wk2/Skipped: Removed a test that no longer crashes thanks to this fix.
* plugins/npp-set-window-called-during-destruction-expected.txt: Added.
* plugins/npp-set-window-called-during-destruction.html: Added.
* platform/mac/plugins/npp-set-window-called-during-destruction-expected.txt: Added. This is
different from the cross-platform results because we don't expect NPP_SetWindow to be called
during destruction.
* platform/win/plugins/npp-set-window-called-during-destruction-expected.txt: Added. This is
a copy of the cross-platform results, needed to override the Mac-specific results.
2011-04-08 Yi Shen <yi.4.shen@nokia.com>
Reviewed by Antonio Gomes.
CONSOLE MESSAGE: line 0: PLUGIN: Success: NPP_SetWindow was not called during plugin destruction
This tests whether a NPP_SetWindow is called during plugin destruction.
......@@ -195,9 +195,6 @@ http/tests/media/video-buffered.html
# Crashes http://webkit.org/b/55778
fast/frames/iframe-plugin-load-remove-document-crash.html
# Causes next test to crash? http://webkit.org/b/55780
platform/win/plugins/draws-gradient.html
# No keygen support
fast/html/keygen.html
fast/invalid/residual-style.html
......
CONSOLE MESSAGE: line 0: PLUGIN: Success: NPP_SetWindow was called during plugin destruction
This tests whether a NPP_SetWindow is called during plugin destruction.
CONSOLE MESSAGE: line 0: PLUGIN: Success: NPP_SetWindow was called during plugin destruction
This tests whether a NPP_SetWindow is called during plugin destruction.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<embed type="application/x-webkit-test-netscape" test="npp-set-window-called-during-destruction"></embed>
<p>This tests whether a NPP_SetWindow is called during plugin destruction.</p>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
var embed = document.getElementsByTagName("embed")[0];
embed.setWillBeDestroyed();
embed.parentNode.removeChild(embed);
</script>
</body>
</html>
2011-04-07 Adam Roben <aroben@apple.com>
Pass NPP_SetWindow a null window handle during plugin destruction on non-Mac platforms
This matches WebKit1.
Fixes <http://webkit.org/b/47009> WebKit2 needs to call NPP_SetWindow when destroying a
plugin
Reviewed by Anders Carlsson.
* WebProcess/Plugins/Netscape/NetscapePlugin.cpp:
(WebKit::NetscapePlugin::destroy): Null out our NPWindow's window handle and pass it to
NPP_SetWindow (unless we're on Mac).
2011-04-08 Jamie Cooley <james.cooley@nokia.com>
Reviewed by Benjamin Poulain.
......
......@@ -491,6 +491,11 @@ void NetscapePlugin::destroy()
// Stop all streams.
stopAllStreams();
#if !PLUGIN_ARCHITECTURE(MAC)
m_npWindow.window = 0;
callSetWindow();
#endif
NPP_Destroy(0);
m_isStarted = false;
......
2011-04-07 Adam Roben <aroben@apple.com>
Test that NPP_SetWindow is passed a null window handle during plugin destruction on non-Mac platforms
Test for <http://webkit.org/b/47009> WebKit2 needs to call NPP_SetWindow when destroying a
plugin
Reviewed by Anders Carlsson.
* DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
(pluginLogWithArguments): Moved code to format and log the message here...
(pluginLog): ...from here.
* DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Added pluginLogWithArguments.
* DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
(PluginTest::log): Added. Calls through to pluginLogWithArguments.
* DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added log.
* DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp: Added.
(NPPSetWindowCalledDuringDestruction::setWillBeDestroyed): Records that destruction is about
to begin.
(NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction): Simple
constructor.
(NPPSetWindowCalledDuringDestruction::NPP_GetValue): Creates and returns a ScriptObject that
can be used to invoke our setWillBeDestroyed function.
(NPPSetWindowCalledDuringDestruction::NPP_SetWindow): Records what has happened (and logs if
anything unexpected happens).
(NPPSetWindowCalledDuringDestruction::NPP_Destroy): On Mac, logs a failure message if
NPP_SetWindow was called during destruction. On other platforms, logs a failure message if
NPP_SetWindow was *not* called during destruction.
(NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod): Return true for our only
method, setWillBeDestroyed.
(NPPSetWindowCalledDuringDestruction::ScriptObject::invoke): Call through to the PluginTest
object.
* DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
* DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
* DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
* GNUmakefile.am:
Added new test.
* Scripts/old-run-webkit-tests: Skip the new test when using out-of-process plugins with
WebKit1 on Mac, since it can't work properly due to <http://webkit.org/b/58077>.
2011-04-08 Mario Sanchez Prada <msanchez@igalia.com>
Reviewed by Martin Robinson.
......
......@@ -139,6 +139,7 @@
BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; };
BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; };
BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; };
C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */; };
C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */; };
C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */; };
C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */; };
......@@ -323,6 +324,7 @@
BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityController.cpp; sourceTree = "<group>"; };
BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityControllerMac.mm; path = mac/AccessibilityControllerMac.mm; sourceTree = "<group>"; };
BCF6C64F0C98E9C000AC063E /* GCController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GCController.cpp; sourceTree = "<group>"; };
C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPPSetWindowCalledDuringDestruction.cpp; sourceTree = "<group>"; };
C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PassDifferentNPPStruct.cpp; sourceTree = "<group>"; };
C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EvaluateJSAfterRemovingPluginElement.cpp; sourceTree = "<group>"; };
C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullNPPGetValuePointer.cpp; sourceTree = "<group>"; };
......@@ -487,6 +489,7 @@
1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */,
1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */,
1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */,
C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */,
1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */,
1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */,
C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */,
......@@ -793,6 +796,7 @@
1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */,
1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */,
1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */,
C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -73,14 +73,10 @@ static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP in
pluginLogWithWindowObject(windowObject, instance, message);
}
// Helper function to log to the console object.
void pluginLog(NPP instance, const char* format, ...)
void pluginLogWithArguments(NPP instance, const char* format, va_list args)
{
va_list args;
va_start(args, format);
char message[2048] = "PLUGIN: ";
vsprintf(message + strlen(message), format, args);
va_end(args);
NPObject* windowObject = 0;
NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
......@@ -93,6 +89,15 @@ void pluginLog(NPP instance, const char* format, ...)
browser->releaseobject(windowObject);
}
// Helper function to log to the console object.
void pluginLog(NPP instance, const char* format, ...)
{
va_list args;
va_start(args, format);
pluginLogWithArguments(instance, format, args);
va_end(args);
}
static void pluginInvalidate(NPObject*);
static bool pluginHasProperty(NPObject*, NPIdentifier name);
static bool pluginHasMethod(NPObject*, NPIdentifier name);
......
......@@ -87,6 +87,7 @@ extern void handleCallback(PluginObject* object, const char *url, NPReason reaso
extern void notifyStream(PluginObject* object, const char *url, const char *headers);
extern void testNPRuntime(NPP npp);
extern void pluginLog(NPP instance, const char* format, ...);
extern void pluginLogWithArguments(NPP instance, const char* format, va_list args);
extern bool testDocumentOpen(NPP npp);
extern bool testWindowOpen(NPP npp);
......
......@@ -25,6 +25,7 @@
#include "PluginTest.h"
#include "PluginObject.h"
#include <assert.h>
#include <string.h>
......@@ -168,6 +169,14 @@ void PluginTest::executeScript(const char* script)
browser->releasevariantvalue(&browserResult);
}
void PluginTest::log(const char* format, ...)
{
va_list args;
va_start(args, format);
pluginLogWithArguments(m_npp, format, args);
va_end(args);
}
void PluginTest::waitUntilDone()
{
executeScript("layoutTestController.waitUntilDone()");
......
......@@ -78,6 +78,7 @@ public:
#endif
void executeScript(const char*);
void log(const char* format, ...);
void registerNPShutdownFunction(void (*)());
......
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "PluginTest.h"
#include "PluginObject.h"
using namespace std;
// NPP_SetWindow should be called with a null window handle as destruction begins on non-Mac platforms.
class NPPSetWindowCalledDuringDestruction : public PluginTest {
public:
NPPSetWindowCalledDuringDestruction(NPP, const string& identifier);
void setWillBeDestroyed() { m_willBeDestroyed = true; }
private:
struct ScriptObject : Object<ScriptObject> {
bool hasMethod(NPIdentifier);
bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*);
};
virtual NPError NPP_GetValue(NPPVariable, void*);
virtual NPError NPP_SetWindow(NPP, NPWindow*);
virtual NPError NPP_Destroy(NPSavedData**);
bool m_willBeDestroyed;
bool m_setWindowCalledBeforeDestruction;
bool m_setWindowCalledDuringDestruction;
};
static PluginTest::Register<NPPSetWindowCalledDuringDestruction> registrar("npp-set-window-called-during-destruction");
NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction(NPP npp, const string& identifier)
: PluginTest(npp, identifier)
, m_willBeDestroyed(false)
, m_setWindowCalledBeforeDestruction(false)
, m_setWindowCalledDuringDestruction(false)
{
}
NPError NPPSetWindowCalledDuringDestruction::NPP_GetValue(NPPVariable variable, void* value)
{
if (variable != NPPVpluginScriptableNPObject)
return NPERR_GENERIC_ERROR;
*static_cast<NPObject**>(value) = ScriptObject::create(this);
return NPERR_NO_ERROR;
}
NPError NPPSetWindowCalledDuringDestruction::NPP_SetWindow(NPP, NPWindow* window)
{
if (m_willBeDestroyed) {
m_setWindowCalledDuringDestruction = true;
if (!m_setWindowCalledBeforeDestruction) {
log("Fail: setWillBeDestroyed() was called before the initial NPP_SetWindow call");
return NPERR_NO_ERROR;
}
#ifndef XP_MACOSX
if (window->window)
log("Fail: NPP_SetWindow passed a non-null window during plugin destruction");
#endif
return NPERR_NO_ERROR;
}
if (m_setWindowCalledBeforeDestruction) {
log("Fail: NPP_SetWindow called more than once before plugin destruction");
return NPERR_NO_ERROR;
}
m_setWindowCalledBeforeDestruction = true;
return NPERR_NO_ERROR;
}
NPError NPPSetWindowCalledDuringDestruction::NPP_Destroy(NPSavedData**)
{
#ifdef XP_MACOSX
bool shouldHaveBeenCalledDuringDestruction = false;
#else
bool shouldHaveBeenCalledDuringDestruction = true;
#endif
if (m_setWindowCalledDuringDestruction == shouldHaveBeenCalledDuringDestruction)
log("Success: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was" : "was not");
else
log("Fail: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was not" : "was");
return NPERR_NO_ERROR;
}
bool NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod(NPIdentifier methodName)
{
return methodName == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed");
}
bool NPPSetWindowCalledDuringDestruction::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*)
{
assert(identifier == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed"));
static_cast<NPPSetWindowCalledDuringDestruction*>(pluginTest())->setWillBeDestroyed();
return true;
}
......@@ -409,6 +409,10 @@
RelativePath="..\Tests\NPDeallocateCalledBeforeNPShutdown.cpp"
>
</File>
<File
RelativePath="..\Tests\NPPSetWindowCalledDuringDestruction.cpp"
>
</File>
<File
RelativePath="..\Tests\NPRuntimeObjectFromDestroyedPlugin.cpp"
>
......
......@@ -33,6 +33,7 @@ SOURCES = PluginObject.cpp \
Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \
Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
Tests/NPDeallocateCalledBeforeNPShutdown.cpp \
Tests/NPPSetWindowCalledDuringDestruction.cpp \
Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
Tests/NPRuntimeRemoveProperty.cpp \
Tests/NullNPPGetValuePointer.cpp \
......
......@@ -183,6 +183,7 @@ TestNetscapePlugin_libtestnetscapeplugin_la_SOURCES = \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp \
Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp \
......
......@@ -600,6 +600,12 @@ if (!checkWebCoreFeatureSupport("XHTMLMP", 0)) {
$ignoredDirectories{'fast/xhtmlmp'} = 1;
}
if (isAppleMacWebKit() && $platform ne "mac-wk2" && osXVersion()->{minor} >= 6 && architecture() =~ /x86_64/) {
# This test relies on executing JavaScript during NPP_Destroy, which isn't supported with
# out-of-process plugins in WebKit1. See <http://webkit.org/b/58077>.
$ignoredFiles{'plugins/npp-set-window-called-during-destruction.html'} = 1;
}
processIgnoreTests(join(',', @ignoreTests), "ignore-tests") if @ignoreTests;
if (!$ignoreSkipped) {
if (!$skippedOnly || @ARGV == 0) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment