Title: [268370] trunk/Tools
Revision
268370
Author
wei...@apple.com
Date
2020-10-12 14:54:50 -0700 (Mon, 12 Oct 2020)

Log Message

Share TestFeatures and TestCommand infrastructure between DumpRenderTree and WebKitTestRunner
https://bugs.webkit.org/show_bug.cgi?id=217614

Reviewed by Dean Jackson.

Move TestFeatures and TestCommand code from WebKitTestRunner to TestRunnerShared
and adopt shared code in both WebKitTestRunner and DumpRenderTree.

This allows us to remove duplicate argument and test header parsing code and
avoid updating both when we want want change things.

To support different sets of test header options, featureDefaultsFromTestHeaderForTest now
has a parameter for a key type map, rather than the old hardcoded set. This allows
WebKitTestRunner and DumpRenderTree, which currently have slightly different options
to continue to behave in the same way. Eventually, it will probably make sense to have these
mostly generated from the WebPreferences*.yaml configuration files.

Matching precedent, shared files use the WTR namespace.

* DumpRenderTree/CMakeLists.txt:
* DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
* TestRunnerShared/CMakeLists.txt:
* WebKitTestRunner/CMakeLists.txt:
* WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
Add new files.

* DumpRenderTree/DumpRenderTree.h:
Removes TestCommand and parseInputLine now that they come from shared TestCommand.h

* DumpRenderTree/DumpRenderTreeCommon.cpp: Removed.
Moved contents to shared TestCommand.cpp

* DumpRenderTree/TestOptions.cpp:
* DumpRenderTree/TestOptions.h:
Adopt model from WebKitTestRunner and use initialization from TestFeatures.

* DumpRenderTree/mac/DumpRenderTree.mm:
Adopt shared TestFeatures and TestCommand infrastructure. Construct TestOptions
in a similar manner to WebKitTestRunner by merging together hardcoded / path based
features and test header based features.

* DumpRenderTree/mac/UIDelegate.h:
* DumpRenderTree/mac/UIDelegate.mm:
Update for new namespace.

* TestRunnerShared/TestCommand.cpp: Added.
* TestRunnerShared/TestCommand.h: Added.
* TestRunnerShared/TestFeatures.cpp: Added.
* TestRunnerShared/TestFeatures.h: Added.
* WebKitTestRunner/TestController.cpp:
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestOptions.cpp:
* WebKitTestRunner/TestOptions.h:
Moved from WebKitTestRunner. Generalized to TestFeatures to take a key type map,
rather than hard coding it. Replace use of WebKit types, like WKURLRef, with std::string
and std::filesystem::path.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Tools/ChangeLog (268369 => 268370)


--- trunk/Tools/ChangeLog	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/ChangeLog	2020-10-12 21:54:50 UTC (rev 268370)
@@ -1,3 +1,62 @@
+2020-10-12  Sam Weinig  <wei...@apple.com>
+
+        Share TestFeatures and TestCommand infrastructure between DumpRenderTree and WebKitTestRunner
+        https://bugs.webkit.org/show_bug.cgi?id=217614
+
+        Reviewed by Dean Jackson.
+
+        Move TestFeatures and TestCommand code from WebKitTestRunner to TestRunnerShared
+        and adopt shared code in both WebKitTestRunner and DumpRenderTree.
+        
+        This allows us to remove duplicate argument and test header parsing code and
+        avoid updating both when we want want change things.
+        
+        To support different sets of test header options, featureDefaultsFromTestHeaderForTest now
+        has a parameter for a key type map, rather than the old hardcoded set. This allows
+        WebKitTestRunner and DumpRenderTree, which currently have slightly different options
+        to continue to behave in the same way. Eventually, it will probably make sense to have these
+        mostly generated from the WebPreferences*.yaml configuration files.
+
+        Matching precedent, shared files use the WTR namespace. 
+
+        * DumpRenderTree/CMakeLists.txt:
+        * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+        * TestRunnerShared/CMakeLists.txt:
+        * WebKitTestRunner/CMakeLists.txt:
+        * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+        Add new files.
+
+        * DumpRenderTree/DumpRenderTree.h:
+        Removes TestCommand and parseInputLine now that they come from shared TestCommand.h
+
+        * DumpRenderTree/DumpRenderTreeCommon.cpp: Removed.
+        Moved contents to shared TestCommand.cpp
+        
+        * DumpRenderTree/TestOptions.cpp:
+        * DumpRenderTree/TestOptions.h:
+        Adopt model from WebKitTestRunner and use initialization from TestFeatures.
+
+        * DumpRenderTree/mac/DumpRenderTree.mm:
+        Adopt shared TestFeatures and TestCommand infrastructure. Construct TestOptions
+        in a similar manner to WebKitTestRunner by merging together hardcoded / path based
+        features and test header based features.
+ 
+        * DumpRenderTree/mac/UIDelegate.h:
+        * DumpRenderTree/mac/UIDelegate.mm:
+        Update for new namespace.
+
+        * TestRunnerShared/TestCommand.cpp: Added.
+        * TestRunnerShared/TestCommand.h: Added.
+        * TestRunnerShared/TestFeatures.cpp: Added.
+        * TestRunnerShared/TestFeatures.h: Added.
+        * WebKitTestRunner/TestController.cpp:
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestOptions.cpp:
+        * WebKitTestRunner/TestOptions.h:
+        Moved from WebKitTestRunner. Generalized to TestFeatures to take a key type map,
+        rather than hard coding it. Replace use of WebKit types, like WKURLRef, with std::string
+        and std::filesystem::path.
+
 2020-10-12  Luming Yin  <luming_...@apple.com>
 
         [macOS] Workaround for MAC_OS_X_VERSION_MAJOR incorrectly including minor version when building 

Modified: trunk/Tools/DumpRenderTree/CMakeLists.txt (268369 => 268370)


--- trunk/Tools/DumpRenderTree/CMakeLists.txt	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/CMakeLists.txt	2020-10-12 21:54:50 UTC (rev 268370)
@@ -10,7 +10,6 @@
     AccessibilityTextMarker.cpp
     AccessibilityUIElement.cpp
     CyclicRedundancyCheck.cpp
-    DumpRenderTreeCommon.cpp
     GCController.cpp
     _javascript_Threading.cpp
     PixelDumpSupport.cpp

Modified: trunk/Tools/DumpRenderTree/DumpRenderTree.h (268369 => 268370)


--- trunk/Tools/DumpRenderTree/DumpRenderTree.h	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/DumpRenderTree.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -54,14 +54,3 @@
 void dump();
 void displayWebView();
 void displayAndTrackRepaintsWebView();
-
-struct TestCommand {
-    std::string pathOrURL;
-    std::string absolutePath;
-    bool shouldDumpPixels { false };
-    std::string expectedPixelHash;
-    int timeout { 30000 }; // in ms
-    bool dumpJSConsoleLogInStdErr { false };
-};
-
-TestCommand parseInputLine(const std::string&);

Modified: trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj (268369 => 268370)


--- trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj	2020-10-12 21:54:50 UTC (rev 268370)
@@ -109,11 +109,12 @@
 		5DB9AC9E0F722C3600684641 /* WebKitWeightWatcher700.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */; };
 		5DB9AC9F0F722C3600684641 /* WebKitWeightWatcher800.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */; };
 		5DB9ACA00F722C3600684641 /* WebKitWeightWatcher900.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */; };
+		7CFF9BBF2533BB240008009F /* TestFeatures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF9BBE2533BB240008009F /* TestFeatures.cpp */; };
+		7CFF9BC22533BC160008009F /* TestCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF9BC12533BC160008009F /* TestCommand.cpp */; };
 		80045AEE147718E7008290A8 /* AccessibilityNotificationHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */; };
 		8465E2C70FFA8DF2003B8342 /* PixelDumpSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */; };
 		93C78826250C6D3A00C0AA24 /* ReftestFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93C78824250C6D3900C0AA24 /* ReftestFunctions.cpp */; };
 		93C7882E250C717200C0AA24 /* JSBasics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93C78829250C713400C0AA24 /* JSBasics.cpp */; };
-		9830F31F15C81181005AB206 /* DumpRenderTreeCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9830F31E15C81181005AB206 /* DumpRenderTreeCommon.cpp */; };
 		A1158D581892740C0088C17B /* DumpRenderTreeBrowserView.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1158D56189273EB0088C17B /* DumpRenderTreeBrowserView.mm */; };
 		A1158D59189274360088C17B /* PixelDumpSupportIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1158D57189273EB0088C17B /* PixelDumpSupportIOS.mm */; };
 		A134E531188FC27000901D06 /* DumpRenderTreeMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = A134E52F188FC27000901D06 /* DumpRenderTreeMain.mm */; };
@@ -330,6 +331,10 @@
 		53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CyclicRedundancyCheck.h; sourceTree = "<group>"; };
 		5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		7CBBC3221DDFCF9A00786B9D /* TestOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestOptions.h; sourceTree = "<group>"; };
+		7CFF9BBD2533BB240008009F /* TestFeatures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFeatures.h; sourceTree = "<group>"; };
+		7CFF9BBE2533BB240008009F /* TestFeatures.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TestFeatures.cpp; sourceTree = "<group>"; };
+		7CFF9BC02533BC160008009F /* TestCommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestCommand.h; sourceTree = "<group>"; };
+		7CFF9BC12533BC160008009F /* TestCommand.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TestCommand.cpp; sourceTree = "<group>"; };
 		80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessibilityNotificationHandler.h; path = mac/AccessibilityNotificationHandler.h; sourceTree = "<group>"; };
 		80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityNotificationHandler.mm; path = mac/AccessibilityNotificationHandler.mm; sourceTree = "<group>"; };
 		8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PixelDumpSupport.cpp; sourceTree = "<group>"; };
@@ -339,7 +344,6 @@
 		93C78825250C6D3900C0AA24 /* ReftestFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReftestFunctions.h; sourceTree = "<group>"; };
 		93C78829250C713400C0AA24 /* JSBasics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSBasics.cpp; sourceTree = "<group>"; };
 		93C7882B250C713400C0AA24 /* JSBasics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSBasics.h; sourceTree = "<group>"; };
-		9830F31E15C81181005AB206 /* DumpRenderTreeCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DumpRenderTreeCommon.cpp; sourceTree = "<group>"; };
 		A1103B5B1892498F00738C87 /* LayoutTestHelper.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = LayoutTestHelper.xcconfig; path = mac/Configurations/LayoutTestHelper.xcconfig; sourceTree = "<group>"; };
 		A1158D55189273EB0088C17B /* DumpRenderTreeBrowserView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeBrowserView.h; path = ios/DumpRenderTreeBrowserView.h; sourceTree = "<group>"; };
 		A1158D56189273EB0088C17B /* DumpRenderTreeBrowserView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTreeBrowserView.mm; path = ios/DumpRenderTreeBrowserView.mm; sourceTree = "<group>"; };
@@ -499,7 +503,6 @@
 				A134E53418905E6C00901D06 /* config.h */,
 				1A2FB84C178C80920059FD96 /* DefaultPolicyDelegate.h */,
 				1A2FB84D178C80930059FD96 /* DefaultPolicyDelegate.mm */,
-				9830F31E15C81181005AB206 /* DumpRenderTreeCommon.cpp */,
 				32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */,
 				1422A2750AF6F4BD00E1A883 /* Delegates */,
 				1422A2690AF6F45200E1A883 /* Controllers */,
@@ -730,6 +733,10 @@
 				3148A0561E6F90F400D3B316 /* IOSLayoutTestCommunication.h */,
 				93C78824250C6D3900C0AA24 /* ReftestFunctions.cpp */,
 				93C78825250C6D3900C0AA24 /* ReftestFunctions.h */,
+				7CFF9BC12533BC160008009F /* TestCommand.cpp */,
+				7CFF9BC02533BC160008009F /* TestCommand.h */,
+				7CFF9BBE2533BB240008009F /* TestFeatures.cpp */,
+				7CFF9BBD2533BB240008009F /* TestFeatures.h */,
 			);
 			name = TestRunnerShared;
 			path = ../TestRunnerShared;
@@ -1216,7 +1223,6 @@
 				1A2FB84F178C80930059FD96 /* DefaultPolicyDelegate.mm in Sources */,
 				BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */,
 				A1158D581892740C0088C17B /* DumpRenderTreeBrowserView.mm in Sources */,
-				9830F31F15C81181005AB206 /* DumpRenderTreeCommon.cpp in Sources */,
 				BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */,
 				A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */,
 				A8B91ADA0CF3B32F008F91FF /* DumpRenderTreePasteboard.mm in Sources */,
@@ -1249,6 +1255,8 @@
 				F4010B7B24DA201F00A876E2 /* PoseAsClass.mm in Sources */,
 				93C78826250C6D3A00C0AA24 /* ReftestFunctions.cpp in Sources */,
 				BCA18B680C9B08C200114369 /* ResourceLoadDelegate.mm in Sources */,
+				7CFF9BC22533BC160008009F /* TestCommand.cpp in Sources */,
+				7CFF9BBF2533BB240008009F /* TestFeatures.cpp in Sources */,
 				A30A21F82051D8C40008FF42 /* TestOptions.cpp in Sources */,
 				BC0131DA0C9772010087317D /* TestRunner.cpp in Sources */,
 				BCA18B240C9B014B00114369 /* TestRunnerMac.mm in Sources */,

Deleted: trunk/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp (268369 => 268370)


--- trunk/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 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. ``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
- * 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 "config.h"
-#include "DumpRenderTree.h"
-
-#include <algorithm>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-
-class CommandTokenizer {
-public:
-    explicit CommandTokenizer(const std::string& input)
-        : m_input(input)
-        , m_posNextSeparator(0)
-    {
-        pump();
-    }
-
-    bool hasNext() const;
-    std::string next();
-
-private:
-    void pump();
-    static const char kSeparator = '\'';
-    const std::string& m_input;
-    std::string m_next;
-    size_t m_posNextSeparator;
-};
-
-void CommandTokenizer::pump()
-{
-    if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
-        m_next = std::string();
-        return;
-    }
-    size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
-    m_posNextSeparator = m_input.find(kSeparator, start);
-    size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
-    m_next = std::string(m_input, start, size);
-}
-
-std::string CommandTokenizer::next()
-{
-    ASSERT(hasNext());
-
-    std::string oldNext = m_next;
-    pump();
-    return oldNext;
-}
-
-bool CommandTokenizer::hasNext() const
-{
-    return !m_next.empty();
-}
-
-NO_RETURN static void die(const std::string& inputLine)
-{
-    fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
-    exit(1);
-}
-
-TestCommand parseInputLine(const std::string& inputLine)
-{
-    TestCommand result;
-    CommandTokenizer tokenizer(inputLine);
-    if (!tokenizer.hasNext())
-        die(inputLine);
-
-    std::string arg = tokenizer.next();
-    result.pathOrURL = arg;
-    while (tokenizer.hasNext()) {
-        arg = tokenizer.next();
-        if (arg == "--timeout") {
-            std::string timeoutToken = tokenizer.next();
-            result.timeout = atoi(timeoutToken.c_str());
-        } else if (arg == "-p" || arg == "--pixel-test") {
-            result.shouldDumpPixels = true;
-            if (tokenizer.hasNext())
-                result.expectedPixelHash = tokenizer.next();
-        } else if (arg == "--dump-jsconsolelog-in-stderr")
-            result.dumpJSConsoleLogInStdErr = true;
-        else if (arg == std::string("--absolutePath"))
-            result.absolutePath = tokenizer.next();
-        else
-            die(inputLine);
-    }
-
-    return result;
-}

Modified: trunk/Tools/DumpRenderTree/TestOptions.cpp (268369 => 268370)


--- trunk/Tools/DumpRenderTree/TestOptions.cpp	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/TestOptions.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -26,140 +26,83 @@
 #include "config.h"
 #include "TestOptions.h"
 
+#include "TestFeatures.h"
 #include <fstream>
 #include <string>
-#include <wtf/text/WTFString.h>
 
-static bool parseBooleanTestHeaderValue(const std::string& value)
+namespace WTR {
+
+const std::unordered_map<std::string, TestHeaderKeyType>& TestOptions::keyTypeMapping()
 {
-    if (value == "true")
-        return true;
-    if (value == "false")
-        return false;
+    static std::unordered_map<std::string, TestHeaderKeyType> map {
+        { "allowCrossOriginSubresourcesToAskForCredentials", TestHeaderKeyType::Bool },
+        { "allowTopNavigationToDataURLs", TestHeaderKeyType::Bool },
+        { "dumpJSConsoleLogInStdErr", TestHeaderKeyType::Bool },
+        { "enableAttachmentElement", TestHeaderKeyType::Bool },
+        { "enableBackForwardCache", TestHeaderKeyType::Bool },
+        { "enableColorFilter", TestHeaderKeyType::Bool },
+        { "enableDragDestinationActionLoad", TestHeaderKeyType::Bool },
+        { "enableInspectorAdditions", TestHeaderKeyType::Bool },
+        { "enableIntersectionObserver", TestHeaderKeyType::Bool },
+        { "enableKeygenElement", TestHeaderKeyType::Bool },
+        { "enableMenuItemElement", TestHeaderKeyType::Bool },
+        { "enableModernMediaControls", TestHeaderKeyType::Bool },
+        { "enablePointerLock", TestHeaderKeyType::Bool },
+        { "layerBackedWebView", TestHeaderKeyType::Bool },
+        { "useAcceleratedDrawing", TestHeaderKeyType::Bool },
+        { "useEphemeralSession", TestHeaderKeyType::Bool },
 
-    LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
-    return false;
-}
+        { "additionalSupportedImageTypes", TestHeaderKeyType::String },
+        { "jscOptions", TestHeaderKeyType::String },
+    };
 
-static bool pathContains(const std::string& pathOrURL, const char* substring)
-{
-    String path(pathOrURL.c_str());
-    return path.contains(substring);
+    return map;
 }
 
-static bool shouldDumpJSConsoleLogInStdErr(const std::string& pathOrURL)
+template<typename T> static void setValueIfSetInMap(T& valueToSet, std::string key, const std::unordered_map<std::string, T>& map)
 {
-    return pathContains(pathOrURL, "localhost:8800/beacon") || pathContains(pathOrURL, "localhost:9443/beacon")
-        || pathContains(pathOrURL, "localhost:8800/cors") || pathContains(pathOrURL, "localhost:9443/cors")
-        || pathContains(pathOrURL, "localhost:8800/fetch") || pathContains(pathOrURL, "localhost:9443/fetch")
-        || pathContains(pathOrURL, "localhost:8800/service-workers") || pathContains(pathOrURL, "localhost:9443/service-workers")
-        || pathContains(pathOrURL, "localhost:8800/streams/writable-streams") || pathContains(pathOrURL, "localhost:9443/streams/writable-streams")
-        || pathContains(pathOrURL, "localhost:8800/streams/piping") || pathContains(pathOrURL, "localhost:9443/streams/piping")
-        || pathContains(pathOrURL, "localhost:8800/xhr") || pathContains(pathOrURL, "localhost:9443/xhr")
-        || pathContains(pathOrURL, "localhost:8800/webrtc") || pathContains(pathOrURL, "localhost:9443/webrtc")
-        || pathContains(pathOrURL, "localhost:8800/websockets") || pathContains(pathOrURL, "localhost:9443/websockets");
+    auto it = map.find(key);
+    if (it == map.end())
+        return;
+    valueToSet = it->second;
 }
 
-TestOptions::TestOptions(const std::string& pathOrURL, const std::string& absolutePath)
+TestOptions::TestOptions(TestFeatures testFeatures)
 {
-    const auto& path = absolutePath.empty() ? pathOrURL : absolutePath;
-    if (path.empty())
-        return;
+    setValueIfSetInMap(allowCrossOriginSubresourcesToAskForCredentials, "allowCrossOriginSubresourcesToAskForCredentials", testFeatures.boolFeatures);
+    setValueIfSetInMap(allowTopNavigationToDataURLs, "allowTopNavigationToDataURLs", testFeatures.boolFeatures);
+    setValueIfSetInMap(dumpJSConsoleLogInStdErr, "dumpJSConsoleLogInStdErr", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableAttachmentElement, "enableAttachmentElement", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableBackForwardCache, "enableBackForwardCache", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableColorFilter, "enableColorFilter", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableDragDestinationActionLoad, "enableDragDestinationActionLoad", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableInspectorAdditions, "enableInspectorAdditions", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableIntersectionObserver, "enableIntersectionObserver", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableKeygenElement, "enableKeygenElement", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableMenuItemElement, "enableMenuItemElement", testFeatures.boolFeatures);
+    setValueIfSetInMap(enableModernMediaControls, "enableModernMediaControls", testFeatures.boolFeatures);
+    setValueIfSetInMap(enablePointerLock, "enablePointerLock", testFeatures.boolFeatures);
+    setValueIfSetInMap(layerBackedWebView, "layerBackedWebView", testFeatures.boolFeatures);
+    setValueIfSetInMap(useAcceleratedDrawing, "useAcceleratedDrawing", testFeatures.boolFeatures);
+    setValueIfSetInMap(useEphemeralSession, "useEphemeralSession", testFeatures.boolFeatures);
 
-    dumpJSConsoleLogInStdErr = shouldDumpJSConsoleLogInStdErr(pathOrURL);
+    setValueIfSetInMap(additionalSupportedImageTypes, "additionalSupportedImageTypes", testFeatures.stringFeatures);
+    setValueIfSetInMap(jscOptions, "jscOptions", testFeatures.stringFeatures);
 
-    std::string options;
-    std::ifstream testFile(path.data());
-    if (!testFile.good())
-        return;
-    getline(testFile, options);
-    std::string beginString("webkit-test-runner [ ");
-    std::string endString(" ]");
-    size_t beginLocation = options.find(beginString);
-    if (beginLocation == std::string::npos)
-        return;
-    size_t endLocation = options.find(endString, beginLocation);
-    if (endLocation == std::string::npos) {
-        LOG_ERROR("Could not find end of test header in %s", path.c_str());
-        return;
-    }
-    std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
-    size_t pairStart = 0;
-    while (pairStart < pairString.size()) {
-        size_t pairEnd = pairString.find(" ", pairStart);
-        if (pairEnd == std::string::npos)
-            pairEnd = pairString.size();
-        size_t equalsLocation = pairString.find("=", pairStart);
-        if (equalsLocation == std::string::npos) {
-            LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", path.c_str());
-            break;
-        }
-        auto key = pairString.substr(pairStart, equalsLocation - pairStart);
-        auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
-        if (key == "enableAttachmentElement")
-            enableAttachmentElement = parseBooleanTestHeaderValue(value);
-        if (key == "useAcceleratedDrawing")
-            useAcceleratedDrawing = parseBooleanTestHeaderValue(value);
-        else if (key == "enableIntersectionObserver")
-            enableIntersectionObserver = parseBooleanTestHeaderValue(value);
-        else if (key == "useEphemeralSession")
-            useEphemeralSession = parseBooleanTestHeaderValue(value);
-        else if (key == "enableBackForwardCache")
-            enableBackForwardCache = parseBooleanTestHeaderValue(value);
-        else if (key == "enableMenuItemElement")
-            enableMenuItemElement = parseBooleanTestHeaderValue(value);
-        else if (key == "enableKeygenElement")
-            enableKeygenElement = parseBooleanTestHeaderValue(value);
-        else if (key == "enableModernMediaControls")
-            enableModernMediaControls = parseBooleanTestHeaderValue(value);
-        else if (key == "enablePointerLock")
-            enablePointerLock = parseBooleanTestHeaderValue(value);
-        else if (key == "enableDragDestinationActionLoad")
-            enableDragDestinationActionLoad = parseBooleanTestHeaderValue(value);
-        else if (key == "layerBackedWebView")
-            layerBackedWebView = parseBooleanTestHeaderValue(value);
-        else if (key == "enableInspectorAdditions")
-            enableInspectorAdditions = parseBooleanTestHeaderValue(value);
-        else if (key == "dumpJSConsoleLogInStdErr")
-            dumpJSConsoleLogInStdErr = parseBooleanTestHeaderValue(value);
-        else if (key == "allowCrossOriginSubresourcesToAskForCredentials")
-            allowCrossOriginSubresourcesToAskForCredentials = parseBooleanTestHeaderValue(value);
-        else if (key == "internal:selectionAcrossShadowBoundariesEnabled")
-            enableSelectionAcrossShadowBoundaries = parseBooleanTestHeaderValue(value);
-        else if (key == "enableColorFilter")
-            enableColorFilter = parseBooleanTestHeaderValue(value);
-        else if (key == "jscOptions")
-            jscOptions = value;
-        else if (key == "additionalSupportedImageTypes")
-            additionalSupportedImageTypes = value;
-        else if (key == "experimental:WebGPUEnabled")
-            enableWebGPU = parseBooleanTestHeaderValue(value);
-        else if (key == "internal:CSSLogicalEnabled")
-            enableCSSLogical = parseBooleanTestHeaderValue(value);
-        else if (key == "internal:LineHeightUnitsEnabled")
-            enableLineHeightUnits = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:AdClickAttributionEnabled")
-            adClickAttributionEnabled = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:ResizeObserverEnabled")
-            enableResizeObserver = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:CSSOMViewSmoothScrollingEnabled")
-            enableCSSOMViewSmoothScrolling = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:CoreMathMLEnabled")
-            enableCoreMathML = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:RequestIdleCallbackEnabled")
-            enableRequestIdleCallback = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:AsyncClipboardAPIEnabled")
-            enableAsyncClipboardAPI = parseBooleanTestHeaderValue(value);
-        else if (key == "internal:LayoutFormattingContextIntegrationEnabled")
-            layoutFormattingContextIntegrationEnabled = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:AspectRatioOfImgFromWidthAndHeightEnabled")
-            enableAspectRatioOfImgFromWidthAndHeight = parseBooleanTestHeaderValue(value);
-        else if (key == "allowTopNavigationToDataURLs")
-            allowTopNavigationToDataURLs = parseBooleanTestHeaderValue(value);
-        else if (key == "experimental:ContactPickerAPIEnabled")
-            enableContactPickerAPI = parseBooleanTestHeaderValue(value);
-        pairStart = pairEnd + 1;
-    }
+    setValueIfSetInMap(enableCSSLogical, "CSSLogicalEnabled", testFeatures.internalDebugFeatures);
+    setValueIfSetInMap(enableLineHeightUnits, "LineHeightUnitsEnabled", testFeatures.internalDebugFeatures);
+    setValueIfSetInMap(enableSelectionAcrossShadowBoundaries, "selectionAcrossShadowBoundariesEnabled", testFeatures.internalDebugFeatures);
+    setValueIfSetInMap(layoutFormattingContextIntegrationEnabled, "LayoutFormattingContextIntegrationEnabled", testFeatures.internalDebugFeatures);
+
+    setValueIfSetInMap(adClickAttributionEnabled, "AdClickAttributionEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableAspectRatioOfImgFromWidthAndHeight, "AspectRatioOfImgFromWidthAndHeightEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableAsyncClipboardAPI, "AsyncClipboardAPIEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableCSSOMViewSmoothScrolling, "CSSOMViewSmoothScrollingEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableContactPickerAPI, "ContactPickerAPIEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableCoreMathML, "CoreMathMLEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableRequestIdleCallback, "RequestIdleCallbackEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableResizeObserver, "ResizeObserverEnabled", testFeatures.experimentalFeatures);
+    setValueIfSetInMap(enableWebGPU, "WebGPUEnabled", testFeatures.experimentalFeatures);
 }
 
 bool TestOptions::webViewIsCompatibleWithOptions(const TestOptions& other) const
@@ -167,3 +110,5 @@
     return other.layerBackedWebView == layerBackedWebView
         && other.jscOptions == jscOptions;
 }
+
+}

Modified: trunk/Tools/DumpRenderTree/TestOptions.h (268369 => 268370)


--- trunk/Tools/DumpRenderTree/TestOptions.h	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/TestOptions.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -25,8 +25,12 @@
 
 #pragma once
 
+#include "TestFeatures.h"
 #include <string>
+#include <unordered_map>
 
+namespace WTR {
+
 struct TestOptions {
     bool enableAttachmentElement { false };
     bool useAcceleratedDrawing { false };
@@ -61,6 +65,11 @@
     std::string jscOptions;
     std::string additionalSupportedImageTypes;
 
-    TestOptions(const std::string& pathOrURL, const std::string& absolutePath);
+    explicit TestOptions(TestFeatures);
     bool webViewIsCompatibleWithOptions(const TestOptions&) const;
+    
+    static const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMapping();
 };
+
+}
+

Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm (268369 => 268370)


--- trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm	2020-10-12 21:54:50 UTC (rev 268370)
@@ -50,6 +50,8 @@
 #import "PolicyDelegate.h"
 #import "PoseAsClass.h"
 #import "ResourceLoadDelegate.h"
+#import "TestCommand.h"
+#import "TestFeatures.h"
 #import "TestOptions.h"
 #import "TestRunner.h"
 #import "UIDelegate.h"
@@ -189,7 +191,7 @@
 NavigationController* gNavigationController = nullptr;
 RefPtr<TestRunner> gTestRunner;
 
-Optional<TestOptions> mainFrameTestOptions;
+Optional<WTR::TestOptions> mainFrameTestOptions;
 WebFrame *mainFrame = nil;
 // This is the topmost frame that is loading, during a given load, or nil when no load is 
 // in progress.  Usually this is the same as the main frame, but not always.  In the case
@@ -966,7 +968,7 @@
     [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain];
 }
 
-static void setWebPreferencesForTestOptions(const TestOptions& options)
+static void setWebPreferencesForTestOptions(const WTR::TestOptions& options)
 {
     WebPreferences *preferences = [WebPreferences standardPreferences];
 
@@ -1816,7 +1818,7 @@
     return strstr(pathOrURL, "w3c/IndexedDB-private-browsing");
 }
 
-static void setJSCOptions(const TestOptions& options)
+static void setJSCOptions(const WTR::TestOptions& options)
 {
     static WTF::StringBuilder savedOptions;
 
@@ -1832,7 +1834,7 @@
 }
 
 enum class ResetTime { BeforeTest, AfterTest };
-static void resetWebViewToConsistentState(const TestOptions& options, ResetTime resetTime)
+static void resetWebViewToConsistentState(const WTR::TestOptions& options, ResetTime resetTime)
 {
     setJSCOptions(options);
 
@@ -1967,11 +1969,20 @@
     return [NSURL fileURLWithPath:absolutePath];
 }
 
+static WTR::TestOptions testOptionsForTest(const WTR::TestCommand& command)
+{
+    WTR::TestFeatures features;
+    WTR::merge(features, WTR::hardcodedFeaturesBasedOnPathForTest(command));
+    WTR::merge(features, WTR::featureDefaultsFromTestHeaderForTest(command, WTR::TestOptions::keyTypeMapping()));
+
+    return WTR::TestOptions { WTFMove(features) };
+}
+
 static void runTest(const string& inputLine)
 {
     ASSERT(!inputLine.empty());
 
-    TestCommand command = parseInputLine(inputLine);
+    auto command = WTR::parseInputLine(inputLine);
     const string& pathOrURL = command.pathOrURL;
     dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests;
 
@@ -1993,7 +2004,7 @@
     auto message = makeString("CRASHING TEST: ", testPath.UTF8String);
     WTF::setCrashLogMessage(message.utf8().data());
 
-    TestOptions options { [url isFileURL] ? [url fileSystemRepresentation] : pathOrURL, command.absolutePath };
+    auto options = testOptionsForTest(command);
 
     if (!mainFrameTestOptions || !options.webViewIsCompatibleWithOptions(mainFrameTestOptions.value())) {
         if (mainFrame)
@@ -2006,7 +2017,7 @@
     const char* testURL([[url absoluteString] UTF8String]);
     gTestRunner = TestRunner::create(testURL, command.expectedPixelHash);
     gTestRunner->setAllowedHosts(allowedHosts);
-    gTestRunner->setCustomTimeout(command.timeout);
+    gTestRunner->setCustomTimeout(command.timeout.milliseconds());
     gTestRunner->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr || options.dumpJSConsoleLogInStdErr);
 
     resetWebViewToConsistentState(options, ResetTime::BeforeTest);

Modified: trunk/Tools/DumpRenderTree/mac/UIDelegate.h (268369 => 268370)


--- trunk/Tools/DumpRenderTree/mac/UIDelegate.h	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/mac/UIDelegate.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -47,6 +47,6 @@
 - (void)resetWindowOrigin;
 - (void)didSetMockGeolocationPermission;
 - (int)numberOfPendingGeolocationPermissionRequests;
-- (void)resetToConsistentStateBeforeTesting:(const TestOptions&)options;
+- (void)resetToConsistentStateBeforeTesting:(const WTR::TestOptions&)options;
 
 @end

Modified: trunk/Tools/DumpRenderTree/mac/UIDelegate.mm (268369 => 268370)


--- trunk/Tools/DumpRenderTree/mac/UIDelegate.mm	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/mac/UIDelegate.mm	2020-10-12 21:54:50 UTC (rev 268370)
@@ -58,7 +58,7 @@
     windowOrigin = NSZeroPoint;
 }
 
-- (void)resetToConsistentStateBeforeTesting:(const TestOptions&)options
+- (void)resetToConsistentStateBeforeTesting:(const WTR::TestOptions&)options
 {
     m_enableDragDestinationActionLoad = options.enableDragDestinationActionLoad;
 }

Modified: trunk/Tools/DumpRenderTree/win/DumpRenderTree.cpp (268369 => 268370)


--- trunk/Tools/DumpRenderTree/win/DumpRenderTree.cpp	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/DumpRenderTree/win/DumpRenderTree.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -38,6 +38,8 @@
 #include "PixelDumpSupport.h"
 #include "PolicyDelegate.h"
 #include "ResourceLoadDelegate.h"
+#include "TestCommand.h"
+#include "TestFeatures.h"
 #include "TestOptions.h"
 #include "TestRunner.h"
 #include "UIDelegate.h"
@@ -911,7 +913,7 @@
     setAlwaysAcceptCookies(false);
 }
 
-static void setWebPreferencesForTestOptions(IWebPreferences* preferences, const TestOptions& options)
+static void setWebPreferencesForTestOptions(IWebPreferences* preferences, const WTR::TestOptions& options)
 {
     COMPtr<IWebPreferencesPrivate8> prefsPrivate { Query, preferences };
 
@@ -963,7 +965,7 @@
 #endif
 }
 
-static void setJSCOptions(const TestOptions& options)
+static void setJSCOptions(const WTR::TestOptions& options)
 {
     static WTF::StringBuilder savedOptions;
 
@@ -978,7 +980,7 @@
     }
 }
 
-static void resetWebViewToConsistentStateBeforeTesting(const TestOptions& options)
+static void resetWebViewToConsistentStateBeforeTesting(const WTR::TestOptions& options)
 {
     setJSCOptions(options);
 
@@ -1165,11 +1167,20 @@
     return false;
 }
 
+static WTR::TestOptions testOptionsForTest(const WTR::TestCommand& command)
+{
+    WTR::TestFeatures features;
+    WTR::merge(features, WTR::hardcodedFeaturesBasedOnPathForTest(command));
+    WTR::merge(features, WTR::featureDefaultsFromTestHeaderForTest(command, WTR::TestOptions::keyTypeMapping()));
+
+    return WTR::TestOptions { WTFMove(features) };
+}
+
 static void runTest(const string& inputLine)
 {
     ASSERT(!inputLine.empty());
 
-    TestCommand command = parseInputLine(inputLine);
+    auto command = WTR::parseInputLine(inputLine);
     const string& pathOrURL = command.pathOrURL;
     dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests;
 
@@ -1213,12 +1224,12 @@
 
     CFRelease(url);
 
-    TestOptions options { command.pathOrURL, command.absolutePath };
+    auto options = testOptionsForTest(command);
 
     resetWebViewToConsistentStateBeforeTesting(options);
 
     ::gTestRunner = TestRunner::create(testURL.data(), command.expectedPixelHash);
-    ::gTestRunner->setCustomTimeout(command.timeout);
+    ::gTestRunner->setCustomTimeout(command.timeout.milliseconds());
     ::gTestRunner->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr || options.dumpJSConsoleLogInStdErr);
 
     topLoadingFrame = nullptr;

Modified: trunk/Tools/TestRunnerShared/CMakeLists.txt (268369 => 268370)


--- trunk/Tools/TestRunnerShared/CMakeLists.txt	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/TestRunnerShared/CMakeLists.txt	2020-10-12 21:54:50 UTC (rev 268370)
@@ -7,6 +7,8 @@
 
 set(TestRunnerShared_SOURCES
     ReftestFunctions.cpp
+    TestCommand.cpp
+    TestFeatures.cpp
 
     Bindings/JSBasics.cpp
     Bindings/JSWrapper.cpp

Copied: trunk/Tools/TestRunnerShared/TestCommand.cpp (from rev 268369, trunk/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp) (0 => 268370)


--- trunk/Tools/TestRunnerShared/TestCommand.cpp	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/TestCommand.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 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 "config.h"
+#include "TestCommand.h"
+
+namespace WTR {
+
+class CommandTokenizer {
+public:
+    explicit CommandTokenizer(const std::string& input)
+        : m_input(input)
+        , m_posNextSeparator(0)
+    {
+        pump();
+    }
+
+    bool hasNext() const;
+    std::string next();
+
+private:
+    void pump();
+    static const char kSeparator = '\'';
+    const std::string& m_input;
+    std::string m_next;
+    size_t m_posNextSeparator;
+};
+
+void CommandTokenizer::pump()
+{
+    if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
+        m_next = std::string();
+        return;
+    }
+    size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
+    m_posNextSeparator = m_input.find(kSeparator, start);
+    size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
+    m_next = std::string(m_input, start, size);
+}
+
+std::string CommandTokenizer::next()
+{
+    ASSERT(hasNext());
+
+    std::string oldNext = m_next;
+    pump();
+    return oldNext;
+}
+
+bool CommandTokenizer::hasNext() const
+{
+    return !m_next.empty();
+}
+
+NO_RETURN static void die(const std::string& inputLine)
+{
+    fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
+    exit(1);
+}
+
+TestCommand parseInputLine(const std::string& inputLine)
+{
+    TestCommand result;
+    CommandTokenizer tokenizer(inputLine);
+    if (!tokenizer.hasNext())
+        die(inputLine);
+
+    std::string arg = tokenizer.next();
+    result.pathOrURL = arg;
+    while (tokenizer.hasNext()) {
+        arg = tokenizer.next();
+        if (arg == "--timeout") {
+            auto timeoutToken = tokenizer.next();
+            result.timeout = Seconds::fromMilliseconds(atoi(timeoutToken.c_str()));
+        } else if (arg == "-p" || arg == "--pixel-test") {
+            result.shouldDumpPixels = true;
+            if (tokenizer.hasNext())
+                result.expectedPixelHash = tokenizer.next();
+        } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
+            result.dumpJSConsoleLogInStdErr = true;
+        else if (arg == std::string("--absolutePath"))
+            result.absolutePath = tokenizer.next();
+        else
+            die(inputLine);
+    }
+    
+    if (result.absolutePath.empty())
+        result.absolutePath = testPath(result.pathOrURL);
+
+    return result;
+}
+
+std::filesystem::path testPath(const std::string& pathOrURL)
+{
+    if (pathOrURL.find("http://") == 0 || pathOrURL.find("https://") == 0)
+        return { };
+
+    if (pathOrURL.find("file://") == 0)
+        return pathOrURL.substr(strlen("file:/"));
+
+    return std::filesystem::absolute(pathOrURL);
+}
+
+std::string testURLString(const std::string& pathOrURL)
+{
+    if (pathOrURL.find("http://") == 0 || pathOrURL.find("https://") == 0 || pathOrURL.find("file://") == 0)
+        return pathOrURL;
+
+    return "file://" + std::filesystem::absolute(pathOrURL).generic_string();
+}
+
+}

Added: trunk/Tools/TestRunnerShared/TestCommand.h (0 => 268370)


--- trunk/Tools/TestRunnerShared/TestCommand.h	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/TestCommand.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <wtf/Seconds.h>
+#include <wtf/StdFilesystem.h>
+
+namespace WTR {
+
+struct TestCommand {
+    std::string pathOrURL;
+    std::filesystem::path absolutePath;
+    std::string expectedPixelHash;
+    WTF::Seconds timeout;
+    bool shouldDumpPixels { false };
+    bool dumpJSConsoleLogInStdErr { false };
+};
+
+TestCommand parseInputLine(const std::string& inputLine);
+
+std::filesystem::path testPath(const std::string& pathOrURL);
+std::string testURLString(const std::string& pathOrURL);
+
+}

Added: trunk/Tools/TestRunnerShared/TestFeatures.cpp (0 => 268370)


--- trunk/Tools/TestRunnerShared/TestFeatures.cpp	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/TestFeatures.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2020 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 "config.h"
+#include "TestFeatures.h"
+
+#include "TestCommand.h"
+#include <fstream>
+#include <string>
+#include <wtf/StdFilesystem.h>
+
+namespace WTR {
+
+void merge(TestFeatures& base, TestFeatures additional)
+{
+    // FIXME: This should use std::unordered_map::merge when it is available for all ports.
+
+    for (auto [key, value] : additional.experimentalFeatures)
+        base.experimentalFeatures.insert_or_assign(key, value);
+    for (auto [key, value] : additional.internalDebugFeatures)
+        base.internalDebugFeatures.insert_or_assign(key, value);
+    for (auto [key, value] : additional.boolFeatures)
+        base.boolFeatures.insert_or_assign(key, value);
+    for (auto [key, value] : additional.doubleFeatures)
+        base.doubleFeatures.insert_or_assign(key, value);
+    for (auto [key, value] : additional.stringFeatures)
+        base.stringFeatures.insert_or_assign(key, value);
+    for (auto [key, value] : additional.stringVectorFeatures)
+        base.stringVectorFeatures.insert_or_assign(key, value);
+}
+
+static bool pathContains(const std::string& pathOrURL, const char* substring)
+{
+    return pathOrURL.find(substring) != std::string::npos;
+}
+
+static bool shouldMakeViewportFlexible(const std::string& pathOrURL)
+{
+    return pathContains(pathOrURL, "viewport/") && !pathContains(pathOrURL, "visual-viewport/");
+}
+
+static bool shouldUseEphemeralSession(const std::string& pathOrURL)
+{
+    return pathContains(pathOrURL, "w3c/IndexedDB-private-browsing") || pathContains(pathOrURL, "w3c\\IndexedDB-private-browsing");
+}
+
+static std::optional<std::pair<double, double>> overrideViewWidthAndHeightForTest(const std::string& pathOrURL)
+{
+    if (pathContains(pathOrURL, "svg/W3C-SVG-1.1") || pathContains(pathOrURL, "svg\\W3C-SVG-1.1"))
+        return { { 480, 360 } };
+    return std::nullopt;
+}
+
+static std::optional<double> overrideDeviceScaleFactorForTest(const std::string& pathOrURL)
+{
+    if (pathContains(pathOrURL, "/hidpi-3x-"))
+        return 3;
+    if (pathContains(pathOrURL, "/hidpi-"))
+        return 2;
+    return std::nullopt;
+}
+
+static bool shouldDumpJSConsoleLogInStdErr(const std::string& pathOrURL)
+{
+    return pathContains(pathOrURL, "localhost:8800/beacon") || pathContains(pathOrURL, "localhost:9443/beacon")
+        || pathContains(pathOrURL, "localhost:8800/cors") || pathContains(pathOrURL, "localhost:9443/cors")
+        || pathContains(pathOrURL, "localhost:8800/fetch") || pathContains(pathOrURL, "localhost:9443/fetch")
+        || pathContains(pathOrURL, "localhost:8800/service-workers") || pathContains(pathOrURL, "localhost:9443/service-workers")
+        || pathContains(pathOrURL, "localhost:8800/streams/writable-streams") || pathContains(pathOrURL, "localhost:9443/streams/writable-streams")
+        || pathContains(pathOrURL, "localhost:8800/streams/piping") || pathContains(pathOrURL, "localhost:9443/streams/piping")
+        || pathContains(pathOrURL, "localhost:8800/xhr") || pathContains(pathOrURL, "localhost:9443/xhr")
+        || pathContains(pathOrURL, "localhost:8800/webrtc") || pathContains(pathOrURL, "localhost:9443/webrtc")
+        || pathContains(pathOrURL, "localhost:8800/websockets") || pathContains(pathOrURL, "localhost:9443/websockets");
+}
+
+TestFeatures hardcodedFeaturesBasedOnPathForTest(const TestCommand& command)
+{
+    TestFeatures features;
+
+    if (shouldMakeViewportFlexible(command.pathOrURL))
+        features.boolFeatures.insert({ "useFlexibleViewport", true });
+    if (shouldUseEphemeralSession(command.pathOrURL))
+        features.boolFeatures.insert({ "useEphemeralSession", true });
+    if (shouldDumpJSConsoleLogInStdErr(command.pathOrURL))
+        features.boolFeatures.insert({ "dumpJSConsoleLogInStdErr", true });
+    if (auto deviceScaleFactor = overrideDeviceScaleFactorForTest(command.pathOrURL); deviceScaleFactor != std::nullopt)
+        features.doubleFeatures.insert({ "deviceScaleFactor", deviceScaleFactor.value() });
+    if (auto viewWidthAndHeight = overrideViewWidthAndHeightForTest(command.pathOrURL); viewWidthAndHeight != std::nullopt) {
+        features.doubleFeatures.insert({ "viewWidth", viewWidthAndHeight->first });
+        features.doubleFeatures.insert({ "viewHeight", viewWidthAndHeight->second });
+    }
+
+    return features;
+}
+
+static bool parseBooleanTestHeaderValue(const std::string& value)
+{
+    if (value == "true")
+        return true;
+    if (value == "false")
+        return false;
+
+    LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
+    return false;
+}
+
+static double parseDoubleTestHeaderValue(const std::string& value)
+{
+    return std::stod(value);
+}
+
+static std::string parseStringTestHeaderValueAsRelativePath(const std::string& value, const std::filesystem::path& testPath)
+{
+    auto basePath = testPath.parent_path();
+    return (basePath / value).generic_string();
+}
+
+static std::string parseStringTestHeaderValueAsURL(const std::string& value)
+{
+    return testURLString(value);
+}
+
+static std::vector<std::string> parseStringTestHeaderValueAsStringVector(const std::string& string)
+{
+    std::vector<std::string> result;
+
+    size_t i = 0;
+    while (i < string.size()) {
+        auto foundIndex = string.find_first_of(',', i);
+
+        if (foundIndex != i)
+            result.push_back(string.substr(i, foundIndex - i));
+
+        if (foundIndex == std::string::npos)
+            break;
+
+        i = foundIndex + 1;
+    }
+
+    return result;
+}
+
+static TestFeatures parseTestHeader(std::filesystem::path path, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
+{
+    auto keyType = [&keyTypeMap](auto& key) {
+        auto it = keyTypeMap.find(key);
+        if (it == keyTypeMap.end())
+            return TestHeaderKeyType::Unknown;
+        return it->second;
+    };
+
+    TestFeatures features;
+    if (!std::filesystem::exists(path))
+        return features;
+
+    std::ifstream file(path);
+    if (!file.good()) {
+        LOG_ERROR("Could not open file to inspect test headers in %s", path.c_str());
+        return features;
+    }
+
+    std::string options;
+    getline(file, options);
+    std::string beginString("webkit-test-runner [ ");
+    std::string endString(" ]");
+    size_t beginLocation = options.find(beginString);
+    if (beginLocation == std::string::npos)
+        return features;
+    size_t endLocation = options.find(endString, beginLocation);
+    if (endLocation == std::string::npos) {
+        LOG_ERROR("Could not find end of test header in %s", path.c_str());
+        return features;
+    }
+    std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
+    size_t pairStart = 0;
+    while (pairStart < pairString.size()) {
+        size_t pairEnd = pairString.find(" ", pairStart);
+        if (pairEnd == std::string::npos)
+            pairEnd = pairString.size();
+        size_t equalsLocation = pairString.find("=", pairStart);
+        if (equalsLocation == std::string::npos) {
+            LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", path.c_str());
+            break;
+        }
+        auto key = pairString.substr(pairStart, equalsLocation - pairStart);
+        auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
+
+        if (key.rfind("experimental:") == 0) {
+            key = key.substr(13);
+            features.experimentalFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
+        } else if (key.rfind("internal:") == 0) {
+            key = key.substr(9);
+            features.internalDebugFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
+        }
+
+        switch (keyType(key)) {
+        case TestHeaderKeyType::Bool:
+            features.boolFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
+            break;
+        case TestHeaderKeyType::Double:
+            features.doubleFeatures.insert({ key, parseDoubleTestHeaderValue(value) });
+            break;
+        case TestHeaderKeyType::String:
+            features.stringFeatures.insert({ key, value });
+            break;
+        case TestHeaderKeyType::StringRelativePath:
+            features.stringFeatures.insert({ key, parseStringTestHeaderValueAsRelativePath(value, path) });
+            break;
+        case TestHeaderKeyType::StringURL:
+            features.stringFeatures.insert({ key, parseStringTestHeaderValueAsURL(value) });
+            break;
+        case TestHeaderKeyType::StringVector:
+            features.stringVectorFeatures.insert({ key, parseStringTestHeaderValueAsStringVector(value) });
+            break;
+        case TestHeaderKeyType::Unknown:
+            LOG_ERROR("Unknown key, '%s, in test header in %s", key.c_str(), path.c_str());
+            break;
+        }
+
+        pairStart = pairEnd + 1;
+    }
+
+    return features;
+}
+
+TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand& command, const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMap)
+{
+    return parseTestHeader(command.absolutePath, keyTypeMap);
+}
+
+}

Added: trunk/Tools/TestRunnerShared/TestFeatures.h (0 => 268370)


--- trunk/Tools/TestRunnerShared/TestFeatures.h	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/TestFeatures.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace WTR {
+
+struct TestCommand;
+
+struct TestFeatures {
+    std::unordered_map<std::string, bool> experimentalFeatures;
+    std::unordered_map<std::string, bool> internalDebugFeatures;
+    std::unordered_map<std::string, bool> boolFeatures;
+    std::unordered_map<std::string, double> doubleFeatures;
+    std::unordered_map<std::string, std::string> stringFeatures;
+    std::unordered_map<std::string, std::vector<std::string>> stringVectorFeatures;
+};
+
+void merge(TestFeatures& base, TestFeatures additional);
+
+TestFeatures hardcodedFeaturesBasedOnPathForTest(const TestCommand&);
+
+enum class TestHeaderKeyType : uint8_t {
+    Bool,
+    Double,
+    String,
+    StringRelativePath,
+    StringURL,
+    StringVector,
+    Unknown
+};
+TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand&, const std::unordered_map<std::string, TestHeaderKeyType>&);
+
+}

Modified: trunk/Tools/WebKitTestRunner/CMakeLists.txt (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/CMakeLists.txt	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/CMakeLists.txt	2020-10-12 21:54:50 UTC (rev 268370)
@@ -28,6 +28,7 @@
 
 set(WebKitTestRunner_INCLUDE_DIRECTORIES
     ${CMAKE_BINARY_DIR}
+    ${WebKitTestRunner_SHARED_DIR}
     ${WebKitTestRunner_BINDINGS_DIR}
     ${WebKitTestRunner_DERIVED_SOURCES_DIR}/UIScriptContext
     ${WebKitTestRunner_DIR}

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -30,6 +30,7 @@
 #include "EventSenderProxy.h"
 #include "Options.h"
 #include "PlatformWebView.h"
+#include "TestCommand.h"
 #include "TestInvocation.h"
 #include "WebCoreTestSupport.h"
 #include <_javascript_Core/InitializeThreading.h>
@@ -1236,24 +1237,6 @@
 }
 #endif
 
-static std::string testPath(WKURLRef url)
-{
-    auto scheme = adoptWK(WKURLCopyScheme(url));
-    if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
-        auto path = adoptWK(WKURLCopyPath(url));
-        auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
-        auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
-        RELEASE_ASSERT(length > 0);
-#if OS(WINDOWS)
-        // Remove the first '/' if it starts with something like "/C:/".
-        if (length >= 4 && buffer[0] == '/' && buffer[2] == ':' && buffer[3] == '/')
-            return std::string(buffer.data() + 1, length - 1);
-#endif
-        return std::string(buffer.data(), length - 1);
-    }
-    return std::string();
-}
-
 WKURLRef TestController::createTestURL(const char* pathOrURL)
 {
     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
@@ -1297,7 +1280,7 @@
     TestFeatures features = m_globalFeatures;
     merge(features, hardcodedFeaturesBasedOnPathForTest(command));
     merge(features, platformSpecificFeatureDefaultsForTest(command));
-    merge(features, featureDefaultsFromTestHeaderForTest(command));
+    merge(features, featureDefaultsFromTestHeaderForTest(command, TestOptions::keyTypeMapping()));
     merge(features, platformSpecificFeatureOverridesDefaultsForTest(command));
 
     return TestOptions { features };
@@ -1345,6 +1328,24 @@
     context->testController.notifyDone();
 }
 
+static std::string testPath(WKURLRef url)
+{
+    auto scheme = adoptWK(WKURLCopyScheme(url));
+    if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
+        auto path = adoptWK(WKURLCopyPath(url));
+        auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
+        auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
+        RELEASE_ASSERT(length > 0);
+#if OS(WINDOWS)
+        // Remove the first '/' if it starts with something like "/C:/".
+        if (length >= 4 && buffer[0] == '/' && buffer[2] == ':' && buffer[3] == '/')
+            return std::string(buffer.data() + 1, length - 1);
+#endif
+        return std::string(buffer.data(), length - 1);
+    }
+    return std::string();
+}
+
 static std::string contentExtensionJSONPath(WKURLRef url)
 {
     auto path = testPath(url);
@@ -1430,97 +1431,13 @@
 
 #endif // !ENABLE(CONTENT_EXTENSIONS)
 
-class CommandTokenizer {
-public:
-    explicit CommandTokenizer(const std::string& input)
-        : m_input(input)
-    {
-        pump();
-    }
-
-    bool hasNext() const;
-    std::string next();
-
-private:
-    void pump();
-    static const char kSeparator = '\'';
-    const std::string& m_input;
-    std::string m_next;
-    size_t m_posNextSeparator { 0 };
-};
-
-void CommandTokenizer::pump()
-{
-    if (m_posNextSeparator == std::string::npos || m_posNextSeparator == m_input.size()) {
-        m_next = std::string();
-        return;
-    }
-    size_t start = m_posNextSeparator ? m_posNextSeparator + 1 : 0;
-    m_posNextSeparator = m_input.find(kSeparator, start);
-    size_t size = m_posNextSeparator == std::string::npos ? std::string::npos : m_posNextSeparator - start;
-    m_next = std::string(m_input, start, size);
-}
-
-std::string CommandTokenizer::next()
-{
-    ASSERT(hasNext());
-
-    std::string oldNext = m_next;
-    pump();
-    return oldNext;
-}
-
-bool CommandTokenizer::hasNext() const
-{
-    return !m_next.empty();
-}
-
-NO_RETURN static void die(const std::string& inputLine)
-{
-    fprintf(stderr, "Unexpected input line: %s\n", inputLine.c_str());
-    exit(1);
-}
-
-static TestCommand parseInputLine(const std::string& inputLine)
-{
-    TestCommand result;
-    CommandTokenizer tokenizer(inputLine);
-    if (!tokenizer.hasNext())
-        die(inputLine);
-
-    std::string arg = tokenizer.next();
-    result.pathOrURL = arg;
-    while (tokenizer.hasNext()) {
-        arg = tokenizer.next();
-        if (arg == std::string("--timeout")) {
-            std::string timeoutToken = tokenizer.next();
-            result.timeout = Seconds::fromMilliseconds(atoi(timeoutToken.c_str()));
-        } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
-            result.shouldDumpPixels = true;
-            if (tokenizer.hasNext())
-                result.expectedPixelHash = tokenizer.next();
-        } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
-            result.dumpJSConsoleLogInStdErr = true;
-        else if (arg == std::string("--absolutePath"))
-            result.absolutePath = tokenizer.next();
-        else
-            die(inputLine);
-    }
-    
-    if (result.absolutePath.empty()) {
-        // Gross. Need to reduce conversions between all the string types and URLs.
-        result.absolutePath = testPath(adoptWK(TestController::createTestURL(result.pathOrURL.c_str())).get());
-    }
-
-    return result;
-}
-
 bool TestController::runTest(const char* inputLine)
 {
     AutodrainedPool pool;
+
+    WKTextCheckerSetTestingMode(true);
     
-    WKTextCheckerSetTestingMode(true);
-    TestCommand command = parseInputLine(std::string(inputLine));
+    auto command = parseInputLine(std::string(inputLine));
 
     m_state = RunningTest;
     

Modified: trunk/Tools/WebKitTestRunner/TestController.h (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/TestController.h	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/TestController.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -644,13 +644,4 @@
 #endif
 };
 
-struct TestCommand {
-    std::string pathOrURL;
-    std::string absolutePath;
-    std::string expectedPixelHash;
-    WTF::Seconds timeout;
-    bool shouldDumpPixels { false };
-    bool dumpJSConsoleLogInStdErr { false };
-};
-
 } // namespace WTR

Modified: trunk/Tools/WebKitTestRunner/TestOptions.cpp (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/TestOptions.cpp	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/TestOptions.cpp	2020-10-12 21:54:50 UTC (rev 268370)
@@ -26,78 +26,13 @@
 #include "config.h"
 #include "TestOptions.h"
 
-#include "StringFunctions.h"
-#include "TestController.h"
 #include <fstream>
-#include <iostream>
 #include <string>
-#include <wtf/Optional.h>
+#include <wtf/Assertions.h>
 #include <wtf/StdFilesystem.h>
-#include <wtf/text/WTFString.h>
 
-#define DUMP_FEATURES 0
-
 namespace WTR {
 
-#if DUMP_FEATURES
-static void dumpFeatures(const TestFeatures& features)
-{
-    if (features.experimentalFeatures.empty() && features.internalDebugFeatures.empty() && features.boolFeatures.empty() && features.doubleFeatures.empty() && features.stringFeatures.empty() && features.stringVectorFeatures.empty()) {
-        std::cerr << "  [EMPTY]\n";
-        return;
-    }
-    
-    if (!features.experimentalFeatures.empty()) {
-        std::cerr << "  Experimental Features: \n";
-        for (auto [key, value] : features.experimentalFeatures)
-            std::cerr << "    " << key << ": " << value << '\n';
-    }
-    if (!features.internalDebugFeatures.empty()) {
-        std::cerr << "  Internal Features: \n";
-        for (auto [key, value] : features.internalDebugFeatures)
-            std::cerr << "    " << key << ": " << value << '\n';
-    }
-    if (!features.boolFeatures.empty()) {
-        std::cerr << "  Bool Features: \n";
-        for (auto [key, value] : features.boolFeatures)
-            std::cerr << "    " << key << ": " << value << '\n';
-    }
-    if (!features.doubleFeatures.empty()) {
-        std::cerr << "  Double Features: \n";
-        for (auto [key, value] : features.doubleFeatures)
-            std::cerr << "    " << key << ": " << value << '\n';
-    }
-    if (!features.stringFeatures.empty()) {
-        std::cerr << "  String Features: \n";
-        for (auto [key, value] : features.stringFeatures)
-            std::cerr << "    " << key << ": " << value << '\n';
-    }
-    if (!features.stringVectorFeatures.empty()) {
-        std::cerr << "  String Vector Features: \n";
-        for (auto [key, value] : features.stringVectorFeatures)
-            std::cerr << "    " << key << ": Number of strings " << value.size() << '\n';
-    }
-}
-#endif
-
-void merge(TestFeatures& base, TestFeatures additional)
-{
-    // FIXME: This should use std::unordered_map::merge when it is available for all ports.
-
-    for (auto [key, value] : additional.experimentalFeatures)
-        base.experimentalFeatures.insert_or_assign(key, value);
-    for (auto [key, value] : additional.internalDebugFeatures)
-        base.internalDebugFeatures.insert_or_assign(key, value);
-    for (auto [key, value] : additional.boolFeatures)
-        base.boolFeatures.insert_or_assign(key, value);
-    for (auto [key, value] : additional.doubleFeatures)
-        base.doubleFeatures.insert_or_assign(key, value);
-    for (auto [key, value] : additional.stringFeatures)
-        base.stringFeatures.insert_or_assign(key, value);
-    for (auto [key, value] : additional.stringVectorFeatures)
-        base.stringVectorFeatures.insert_or_assign(key, value);
-}
-
 static const std::unordered_map<std::string, bool>& boolDefaultsMap()
 {
     static std::unordered_map<std::string, bool> map {
@@ -182,268 +117,76 @@
     return map;
 }
 
-enum class KeyType : uint8_t {
-    Bool,
-    Double,
-    String,
-    StringRelativePath,
-    StringURL,
-    StringVector,
-    Unknown
-};
-
-static const std::unordered_map<std::string, KeyType>& keyTypeMap()
+const std::unordered_map<std::string, TestHeaderKeyType>& TestOptions::keyTypeMapping()
 {
-    static std::unordered_map<std::string, KeyType> map {
-        { "allowCrossOriginSubresourcesToAskForCredentials", KeyType::Bool },
-        { "allowTopNavigationToDataURLs", KeyType::Bool },
-        { "allowsLinkPreview", KeyType::Bool },
-        { "domPasteAllowed", KeyType::Bool },
-        { "dumpJSConsoleLogInStdErr", KeyType::Bool },
-        { "editable", KeyType::Bool },
-        { "enableAppNap", KeyType::Bool },
-        { "enableAttachmentElement", KeyType::Bool },
-        { "enableBackForwardCache", KeyType::Bool },
-        { "enableCaptureAudioInGPUProcess", KeyType::Bool },
-        { "enableCaptureAudioInUIProcess", KeyType::Bool },
-        { "enableCaptureVideoInGPUProcess", KeyType::Bool },
-        { "enableCaptureVideoInUIProcess", KeyType::Bool },
-        { "enableColorFilter", KeyType::Bool },
-        { "enableInAppBrowserPrivacy", KeyType::Bool },
-        { "enableInspectorAdditions", KeyType::Bool },
-        { "enableKeygenElement", KeyType::Bool },
-        { "enableMenuItemElement", KeyType::Bool },
-        { "enableModernMediaControls", KeyType::Bool },
-        { "enableProcessSwapOnNavigation", KeyType::Bool },
-        { "enableProcessSwapOnWindowOpen", KeyType::Bool },
-        { "enableServiceControls", KeyType::Bool },
-        { "enableWebAuthentication", KeyType::Bool },
-        { "enableWebAuthenticationLocalAuthenticator", KeyType::Bool },
-        { "ignoreSynchronousMessagingTimeouts", KeyType::Bool },
-        { "ignoresViewportScaleLimits", KeyType::Bool },
-        { "isAppBoundWebView", KeyType::Bool },
-        { "needsSiteSpecificQuirks", KeyType::Bool },
-        { "punchOutWhiteBackgroundsInDarkMode", KeyType::Bool },
-        { "runSingly", KeyType::Bool },
-        { "shouldHandleRunOpenPanel", KeyType::Bool },
-        { "shouldIgnoreMetaViewport", KeyType::Bool },
-        { "shouldPresentPopovers", KeyType::Bool },
-        { "shouldShowTouches", KeyType::Bool },
-        { "shouldShowWebView", KeyType::Bool },
-        { "spellCheckingDots", KeyType::Bool },
-        { "useAcceleratedDrawing", KeyType::Bool },
-        { "useCharacterSelectionGranularity", KeyType::Bool },
-        { "useDataDetection", KeyType::Bool },
-        { "useEphemeralSession", KeyType::Bool },
-        { "useFlexibleViewport", KeyType::Bool },
-        { "useMockScrollbars", KeyType::Bool },
-        { "useRemoteLayerTree", KeyType::Bool },
-        { "useServiceWorkerShortTimeout", KeyType::Bool },
-        { "useThreadedScrolling", KeyType::Bool },
+    static std::unordered_map<std::string, TestHeaderKeyType> map {
+        { "allowCrossOriginSubresourcesToAskForCredentials", TestHeaderKeyType::Bool },
+        { "allowTopNavigationToDataURLs", TestHeaderKeyType::Bool },
+        { "allowsLinkPreview", TestHeaderKeyType::Bool },
+        { "domPasteAllowed", TestHeaderKeyType::Bool },
+        { "dumpJSConsoleLogInStdErr", TestHeaderKeyType::Bool },
+        { "editable", TestHeaderKeyType::Bool },
+        { "enableAppNap", TestHeaderKeyType::Bool },
+        { "enableAttachmentElement", TestHeaderKeyType::Bool },
+        { "enableBackForwardCache", TestHeaderKeyType::Bool },
+        { "enableCaptureAudioInGPUProcess", TestHeaderKeyType::Bool },
+        { "enableCaptureAudioInUIProcess", TestHeaderKeyType::Bool },
+        { "enableCaptureVideoInGPUProcess", TestHeaderKeyType::Bool },
+        { "enableCaptureVideoInUIProcess", TestHeaderKeyType::Bool },
+        { "enableColorFilter", TestHeaderKeyType::Bool },
+        { "enableInAppBrowserPrivacy", TestHeaderKeyType::Bool },
+        { "enableInspectorAdditions", TestHeaderKeyType::Bool },
+        { "enableKeygenElement", TestHeaderKeyType::Bool },
+        { "enableMenuItemElement", TestHeaderKeyType::Bool },
+        { "enableModernMediaControls", TestHeaderKeyType::Bool },
+        { "enableProcessSwapOnNavigation", TestHeaderKeyType::Bool },
+        { "enableProcessSwapOnWindowOpen", TestHeaderKeyType::Bool },
+        { "enableServiceControls", TestHeaderKeyType::Bool },
+        { "enableWebAuthentication", TestHeaderKeyType::Bool },
+        { "enableWebAuthenticationLocalAuthenticator", TestHeaderKeyType::Bool },
+        { "ignoreSynchronousMessagingTimeouts", TestHeaderKeyType::Bool },
+        { "ignoresViewportScaleLimits", TestHeaderKeyType::Bool },
+        { "isAppBoundWebView", TestHeaderKeyType::Bool },
+        { "needsSiteSpecificQuirks", TestHeaderKeyType::Bool },
+        { "punchOutWhiteBackgroundsInDarkMode", TestHeaderKeyType::Bool },
+        { "runSingly", TestHeaderKeyType::Bool },
+        { "shouldHandleRunOpenPanel", TestHeaderKeyType::Bool },
+        { "shouldIgnoreMetaViewport", TestHeaderKeyType::Bool },
+        { "shouldPresentPopovers", TestHeaderKeyType::Bool },
+        { "shouldShowTouches", TestHeaderKeyType::Bool },
+        { "shouldShowWebView", TestHeaderKeyType::Bool },
+        { "spellCheckingDots", TestHeaderKeyType::Bool },
+        { "useAcceleratedDrawing", TestHeaderKeyType::Bool },
+        { "useCharacterSelectionGranularity", TestHeaderKeyType::Bool },
+        { "useDataDetection", TestHeaderKeyType::Bool },
+        { "useEphemeralSession", TestHeaderKeyType::Bool },
+        { "useFlexibleViewport", TestHeaderKeyType::Bool },
+        { "useMockScrollbars", TestHeaderKeyType::Bool },
+        { "useRemoteLayerTree", TestHeaderKeyType::Bool },
+        { "useServiceWorkerShortTimeout", TestHeaderKeyType::Bool },
+        { "useThreadedScrolling", TestHeaderKeyType::Bool },
     
-        { "contentInset.top", KeyType::Double },
-        { "deviceScaleFactor", KeyType::Double },
-        { "viewHeight", KeyType::Double },
-        { "viewWidth", KeyType::Double },
+        { "contentInset.top", TestHeaderKeyType::Double },
+        { "deviceScaleFactor", TestHeaderKeyType::Double },
+        { "viewHeight", TestHeaderKeyType::Double },
+        { "viewWidth", TestHeaderKeyType::Double },
 
-        { "additionalSupportedImageTypes", KeyType::String },
-        { "applicationBundleIdentifier", KeyType::String },
-        { "applicationManifest", KeyType::StringRelativePath },
-        { "contentMode", KeyType::String },
-        { "jscOptions", KeyType::String },
-        { "standaloneWebApplicationURL", KeyType::StringURL },
+        { "additionalSupportedImageTypes", TestHeaderKeyType::String },
+        { "applicationBundleIdentifier", TestHeaderKeyType::String },
+        { "applicationManifest", TestHeaderKeyType::StringRelativePath },
+        { "contentMode", TestHeaderKeyType::String },
+        { "jscOptions", TestHeaderKeyType::String },
+        { "standaloneWebApplicationURL", TestHeaderKeyType::StringURL },
 
-        { "language", KeyType::StringVector },
+        { "language", TestHeaderKeyType::StringVector },
     };
 
     return map;
 }
 
-static KeyType keyType(std::string key)
-{
-    auto map = keyTypeMap();
-    auto it = map.find(key);
-    if (it == map.end())
-        return KeyType::Unknown;
-    return it->second;
-}
-
-static bool parseBooleanTestHeaderValue(const std::string& value)
-{
-    if (value == "true")
-        return true;
-    if (value == "false")
-        return false;
-
-    LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
-    return false;
-}
-
-static std::string parseStringTestHeaderValueAsRelativePath(const std::string& value, const std::string& pathOrURL)
-{
-    auto baseURL = adoptWK(TestController::createTestURL(pathOrURL.c_str()));
-    auto relativeURL = adoptWK(WKURLCreateWithBaseURL(baseURL.get(), value.c_str()));
-    return toSTD(adoptWK(WKURLCopyPath(relativeURL.get())));
-}
-
-static std::string parseStringTestHeaderValueAsURL(const std::string& value)
-{
-    return toSTD(adoptWK(WKURLCopyString(TestController::createTestURL(value.c_str()))));
-}
-
-static TestFeatures parseTestHeader(std::filesystem::path path, const std::string& pathOrURL)
-{
-    TestFeatures features;
-    if (!std::filesystem::exists(path))
-        return features;
-
-    std::ifstream file(path);
-    if (!file.good()) {
-        LOG_ERROR("Could not open file to inspect test headers in %s", path.c_str());
-        return features;
-    }
-
-    std::string options;
-    getline(file, options);
-    std::string beginString("webkit-test-runner [ ");
-    std::string endString(" ]");
-    size_t beginLocation = options.find(beginString);
-    if (beginLocation == std::string::npos)
-        return features;
-    size_t endLocation = options.find(endString, beginLocation);
-    if (endLocation == std::string::npos) {
-        LOG_ERROR("Could not find end of test header in %s", path.c_str());
-        return features;
-    }
-    std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
-    size_t pairStart = 0;
-    while (pairStart < pairString.size()) {
-        size_t pairEnd = pairString.find(" ", pairStart);
-        if (pairEnd == std::string::npos)
-            pairEnd = pairString.size();
-        size_t equalsLocation = pairString.find("=", pairStart);
-        if (equalsLocation == std::string::npos) {
-            LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", path.c_str());
-            break;
-        }
-        auto key = pairString.substr(pairStart, equalsLocation - pairStart);
-        auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
-
-        if (key.rfind("experimental:") == 0) {
-            key = key.substr(13);
-            features.experimentalFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
-        } else if (key.rfind("internal:") == 0) {
-            key = key.substr(9);
-            features.internalDebugFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
-        }
-
-        switch (keyType(key)) {
-        case KeyType::Bool:
-            features.boolFeatures.insert({ key, parseBooleanTestHeaderValue(value) });
-            break;
-        case KeyType::Double:
-            features.doubleFeatures.insert({ key, std::stod(value) });
-            break;
-        case KeyType::String:
-            features.stringFeatures.insert({ key, value });
-            break;
-        case KeyType::StringRelativePath:
-            features.stringFeatures.insert({ key, parseStringTestHeaderValueAsRelativePath(value, pathOrURL) });
-            break;
-        case KeyType::StringURL:
-            features.stringFeatures.insert({ key, parseStringTestHeaderValueAsURL(value) });
-            break;
-        case KeyType::StringVector:
-            features.stringVectorFeatures.insert({ key, split(value, ',') });
-            break;
-        case KeyType::Unknown:
-            LOG_ERROR("Unknown key, '%s, in test header in %s", key.c_str(), path.c_str());
-            break;
-        }
-
-        pairStart = pairEnd + 1;
-    }
-
-    return features;
-}
-
-static bool pathContains(const std::string& pathOrURL, const char* substring)
-{
-    String path(pathOrURL.c_str());
-    return path.contains(substring); // Case-insensitive.
-}
-
-static bool shouldMakeViewportFlexible(const std::string& pathOrURL)
-{
-    return pathContains(pathOrURL, "viewport/") && !pathContains(pathOrURL, "visual-viewport/");
-}
-
-static bool shouldUseEphemeralSession(const std::string& pathOrURL)
-{
-    return pathContains(pathOrURL, "w3c/IndexedDB-private-browsing") || pathContains(pathOrURL, "w3c\\IndexedDB-private-browsing");
-}
-
-static Optional<std::pair<double, double>> overrideViewWidthAndHeightForTest(const std::string& pathOrURL)
-{
-    if (pathContains(pathOrURL, "svg/W3C-SVG-1.1") || pathContains(pathOrURL, "svg\\W3C-SVG-1.1"))
-        return { { 480, 360 } };
-    return WTF::nullopt;
-}
-
-static Optional<double> overrideDeviceScaleFactorForTest(const std::string& pathOrURL)
-{
-    if (pathContains(pathOrURL, "/hidpi-3x-"))
-        return 3;
-    if (pathContains(pathOrURL, "/hidpi-"))
-        return 2;
-    return WTF::nullopt;
-}
-
-static bool shouldDumpJSConsoleLogInStdErr(const std::string& pathOrURL)
-{
-    return pathContains(pathOrURL, "localhost:8800/beacon") || pathContains(pathOrURL, "localhost:9443/beacon")
-        || pathContains(pathOrURL, "localhost:8800/cors") || pathContains(pathOrURL, "localhost:9443/cors")
-        || pathContains(pathOrURL, "localhost:8800/fetch") || pathContains(pathOrURL, "localhost:9443/fetch")
-        || pathContains(pathOrURL, "localhost:8800/service-workers") || pathContains(pathOrURL, "localhost:9443/service-workers")
-        || pathContains(pathOrURL, "localhost:8800/streams/writable-streams") || pathContains(pathOrURL, "localhost:9443/streams/writable-streams")
-        || pathContains(pathOrURL, "localhost:8800/streams/piping") || pathContains(pathOrURL, "localhost:9443/streams/piping")
-        || pathContains(pathOrURL, "localhost:8800/xhr") || pathContains(pathOrURL, "localhost:9443/xhr")
-        || pathContains(pathOrURL, "localhost:8800/webrtc") || pathContains(pathOrURL, "localhost:9443/webrtc")
-        || pathContains(pathOrURL, "localhost:8800/websockets") || pathContains(pathOrURL, "localhost:9443/websockets");
-}
-
-TestFeatures hardcodedFeaturesBasedOnPathForTest(const TestCommand& command)
-{
-    TestFeatures features;
-
-    if (shouldMakeViewportFlexible(command.pathOrURL))
-        features.boolFeatures.insert({ "useFlexibleViewport", true });
-    if (shouldUseEphemeralSession(command.pathOrURL))
-        features.boolFeatures.insert({ "useEphemeralSession", true });
-    if (shouldDumpJSConsoleLogInStdErr(command.pathOrURL))
-        features.boolFeatures.insert({ "dumpJSConsoleLogInStdErr", true });
-    if (auto deviceScaleFactor = overrideDeviceScaleFactorForTest(command.pathOrURL); deviceScaleFactor != WTF::nullopt)
-        features.doubleFeatures.insert({ "deviceScaleFactor", deviceScaleFactor.value() });
-    if (auto viewWidthAndHeight = overrideViewWidthAndHeightForTest(command.pathOrURL); viewWidthAndHeight != WTF::nullopt) {
-        features.doubleFeatures.insert({ "viewWidth", viewWidthAndHeight->first });
-        features.doubleFeatures.insert({ "viewHeight", viewWidthAndHeight->second });
-    }
-
-    return features;
-}
-
-TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand& command)
-{
-    return parseTestHeader(command.absolutePath, command.pathOrURL);
-}
-
 TestOptions::TestOptions(TestFeatures features)
     : m_features { features }
 {
-#if DUMP_FEATURES
-    std::cerr << "DUMPING FEATURES\n";
-    dumpFeatures(m_features);
-#endif
 }
 
 bool TestOptions::hasSameInitializationOptions(const TestOptions& options) const
@@ -453,27 +196,27 @@
     if (m_features.internalDebugFeatures != options.m_features.internalDebugFeatures)
         return false;
 
-    for (auto [key, keyType] : keyTypeMap()) {
+    for (auto [key, keyType] : keyTypeMapping()) {
         switch (keyType) {
-        case KeyType::Bool:
+        case TestHeaderKeyType::Bool:
             if (boolFeatureValue(key) != options.boolFeatureValue(key))
                 return false;
             break;
-        case KeyType::Double:
+        case TestHeaderKeyType::Double:
             if (doubleFeatureValue(key) != options.doubleFeatureValue(key))
                 return false;
             break;
-        case KeyType::String:
-        case KeyType::StringRelativePath:
-        case KeyType::StringURL:
+        case TestHeaderKeyType::String:
+        case TestHeaderKeyType::StringRelativePath:
+        case TestHeaderKeyType::StringURL:
             if (stringFeatureValue(key) != options.stringFeatureValue(key))
                 return false;
             break;
-        case KeyType::StringVector:
+        case TestHeaderKeyType::StringVector:
             if (stringVectorFeatureValue(key) != options.stringVectorFeatureValue(key))
                 return false;
             break;
-        case KeyType::Unknown:
+        case TestHeaderKeyType::Unknown:
             ASSERT_NOT_REACHED();
         }
     }

Modified: trunk/Tools/WebKitTestRunner/TestOptions.h (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/TestOptions.h	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/TestOptions.h	2020-10-12 21:54:50 UTC (rev 268370)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "TestFeatures.h"
 #include <optional>
 #include <string>
 #include <unordered_map>
@@ -32,22 +33,6 @@
 
 namespace WTR {
 
-struct TestCommand;
-
-struct TestFeatures {
-    std::unordered_map<std::string, bool> experimentalFeatures;
-    std::unordered_map<std::string, bool> internalDebugFeatures;
-    std::unordered_map<std::string, bool> boolFeatures;
-    std::unordered_map<std::string, double> doubleFeatures;
-    std::unordered_map<std::string, std::string> stringFeatures;
-    std::unordered_map<std::string, std::vector<std::string>> stringVectorFeatures;
-};
-
-void merge(TestFeatures& base, TestFeatures additional);
-
-TestFeatures hardcodedFeaturesBasedOnPathForTest(const TestCommand&);
-TestFeatures featureDefaultsFromTestHeaderForTest(const TestCommand&);
-
 struct ContextOptions {
     std::vector<std::string> overrideLanguages;
     bool ignoreSynchronousMessagingTimeouts;
@@ -74,6 +59,8 @@
 
 class TestOptions {
 public:
+    static const std::unordered_map<std::string, TestHeaderKeyType>& keyTypeMapping();
+
     explicit TestOptions(TestFeatures);
 
     ContextOptions contextOptions() const

Modified: trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj (268369 => 268370)


--- trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj	2020-10-12 21:35:07 UTC (rev 268369)
+++ trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj	2020-10-12 21:54:50 UTC (rev 268370)
@@ -120,6 +120,8 @@
 		6510A78B11EC643800410867 /* WebKitWeightWatcher800.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */; };
 		6510A78C11EC643800410867 /* WebKitWeightWatcher900.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */; };
 		65EB85A011EC67CC0034D300 /* ActivateFontsCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65EB859F11EC67CC0034D300 /* ActivateFontsCocoa.mm */; };
+		7CFF9BCA2534AF1D0008009F /* TestFeatures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF9BC62534AF1D0008009F /* TestFeatures.cpp */; };
+		7CFF9BCB2534AF1D0008009F /* TestCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CFF9BC72534AF1D0008009F /* TestCommand.cpp */; };
 		8034C6621487636400AC32E9 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8034C6611487636400AC32E9 /* AccessibilityControllerMac.mm */; };
 		8097338A14874A5A008156D9 /* AccessibilityNotificationHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8097338914874A5A008156D9 /* AccessibilityNotificationHandler.mm */; };
 		9376417A210D737200A3DAAE /* WebKitTestRunnerWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93764176210D736000A3DAAE /* WebKitTestRunnerWindow.mm */; };
@@ -349,6 +351,10 @@
 		6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher900.ttf; path = fonts/WebKitWeightWatcher900.ttf; sourceTree = "<group>"; };
 		65EB859D11EC67CC0034D300 /* ActivateFonts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivateFonts.h; sourceTree = "<group>"; };
 		65EB859F11EC67CC0034D300 /* ActivateFontsCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActivateFontsCocoa.mm; sourceTree = "<group>"; };
+		7CFF9BC52534AF1D0008009F /* TestFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestFeatures.h; path = ../TestRunnerShared/TestFeatures.h; sourceTree = "<group>"; };
+		7CFF9BC62534AF1D0008009F /* TestFeatures.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestFeatures.cpp; path = ../TestRunnerShared/TestFeatures.cpp; sourceTree = "<group>"; };
+		7CFF9BC72534AF1D0008009F /* TestCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestCommand.cpp; path = ../TestRunnerShared/TestCommand.cpp; sourceTree = "<group>"; };
+		7CFF9BC82534AF1D0008009F /* TestCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestCommand.h; path = ../TestRunnerShared/TestCommand.h; sourceTree = "<group>"; };
 		8034C6611487636400AC32E9 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AccessibilityControllerMac.mm; sourceTree = "<group>"; };
 		8097338814874A5A008156D9 /* AccessibilityNotificationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessibilityNotificationHandler.h; path = mac/AccessibilityNotificationHandler.h; sourceTree = "<group>"; };
 		8097338914874A5A008156D9 /* AccessibilityNotificationHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityNotificationHandler.mm; path = mac/AccessibilityNotificationHandler.mm; sourceTree = "<group>"; };
@@ -355,7 +361,6 @@
 		841CC00D181185BF0042E9B6 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
 		841CC00E181185BF0042E9B6 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
 		8DD76FA10486AA7600D96B5E /* WebKitTestRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WebKitTestRunner; sourceTree = BUILT_PRODUCTS_DIR; };
-		9338D1BA250A79EB00E827F6 /* JSBasics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JSBasics.h; path = ../TestRunnerShared/Bindings/JSBasics.h; sourceTree = "<group>"; };
 		9338D1BE250BD9DD00E827F6 /* DictionaryFunctions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DictionaryFunctions.h; sourceTree = "<group>"; };
 		93764176210D736000A3DAAE /* WebKitTestRunnerWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebKitTestRunnerWindow.mm; sourceTree = "<group>"; };
 		93764177210D736100A3DAAE /* WebKitTestRunnerWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitTestRunnerWindow.h; sourceTree = "<group>"; };
@@ -549,6 +554,10 @@
 				3148A0541E6F85B600D3B316 /* IOSLayoutTestCommunication.h */,
 				93C7881F250C69E400C0AA24 /* ReftestFunctions.cpp */,
 				93C78820250C69E400C0AA24 /* ReftestFunctions.h */,
+				7CFF9BC72534AF1D0008009F /* TestCommand.cpp */,
+				7CFF9BC82534AF1D0008009F /* TestCommand.h */,
+				7CFF9BC62534AF1D0008009F /* TestFeatures.cpp */,
+				7CFF9BC52534AF1D0008009F /* TestFeatures.h */,
 			);
 			name = TestRunnerShared;
 			sourceTree = "<group>";
@@ -1209,8 +1218,10 @@
 				2E2A765D2370C8D1008F9FFE /* PlatformViewHelpers.mm in Sources */,
 				F4010B7E24DA205300A876E2 /* PoseAsClass.mm in Sources */,
 				2DFA98491D7F70CF00AFF2C9 /* SharedEventStreamsMac.mm in Sources */,
+				7CFF9BCB2534AF1D0008009F /* TestCommand.cpp in Sources */,
 				A18510411B9AE13800744AEB /* TestController.cpp in Sources */,
 				A185103B1B9AE0E200744AEB /* TestControllerCocoa.mm in Sources */,
+				7CFF9BCA2534AF1D0008009F /* TestFeatures.cpp in Sources */,
 				A18510421B9AE13E00744AEB /* TestInvocation.cpp in Sources */,
 				A185103D1B9AE10600744AEB /* TestInvocationCG.cpp in Sources */,
 				0F622CE91BBB3A1A00838AD3 /* TestOptions.cpp in Sources */,
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to