diff --git a/BUILD.gn b/BUILD.gn index b804a562..9e0e2fd8 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -267,6 +267,10 @@ "//ui/ozone/gl:ozone_gl_unittests", ] } + + if (ozone_platform_x11) { + deps += [ "//ui/ozone:ozone_x11_unittests" ] + } } if (use_x11 || ozone_platform_x11) {
diff --git a/DEPS b/DEPS index 4cb13098..4d4a9ed0 100644 --- a/DEPS +++ b/DEPS
@@ -313,7 +313,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'caeea330067c6b166a877f1198cf9a7534c2a3d4', + 'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '3d171a2fcf084cfbafe35eb910c3df2883a1a0cc', 'condition': 'checkout_linux', }, @@ -404,7 +404,7 @@ Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'a9bac57ce6c9d390a52ebaad3259f5fdb871210e', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '26f7d8ad2f7c6c902825a985146a1d9d68e783cb', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'e3b480d3be4446ea17011c0cdc9c4cd380a5c58f', 'src/third_party/jsoncpp/source': Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java index 06bf771..e95e04c 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java +++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
@@ -293,6 +293,27 @@ notifyVirtualValueChanged(index); } + @Override + public void onTextFieldDidScroll(int index, float x, float y, float width, float height) { + // crbug.com/730764 - from P and above, Android framework listens to the onScrollChanged() + // and repositions the autofill UI automatically. + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) return; + if (mRequest == null) return; + + short sIndex = (short) index; + FocusField focusField = mRequest.getFocusField(); + if (focusField == null || sIndex != focusField.fieldIndex) return; + + int virtualId = mRequest.getVirtualId(sIndex); + Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height)); + // Notify the new position to the Android framework. Note that we do not call + // notifyVirtualViewExited() here intentionally to avoid flickering. + mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound); + + // Update focus field position. + mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound)); + } + private void notifyVirtualValueChanged(int index) { AutofillValue autofillValue = mRequest.getFieldNewValue(index); if (autofillValue == null) return;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java index 0c7cf09..e35cdbd 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
@@ -518,16 +518,32 @@ @Test @SmallTest @Feature({"AndroidWebView"}) - public void testTouchingFormBasicTest() throws Throwable { - // Currently, touching form triggers autofill only when the app resizes on showing soft - // input keyboard. (https://crbug.com/730764) - ThreadUtils.runOnUiThreadBlocking(new Runnable() { + public void testTouchingFormWithAdjustResize() throws Throwable { + ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { mRule.getActivity().getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } }); + internalTestTriggerTest(); + } + + @Test + @SmallTest + @Feature({"AndroidWebView"}) + public void testTouchingFormWithAdjustPan() throws Throwable { + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mRule.getActivity().getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + } + }); + internalTestTriggerTest(); + } + + private void internalTestTriggerTest() throws Throwable { TestWebServer webServer = TestWebServer.start(); final String data = "<html><head></head><body><form action='a.html' name='formname'>" + "<input type='text' id='text1' name='username'"
diff --git a/build/android/buildhooks/OWNERS b/build/android/buildhooks/OWNERS index a512a5a..c964495 100644 --- a/build/android/buildhooks/OWNERS +++ b/build/android/buildhooks/OWNERS
@@ -1,5 +1,4 @@ agrieve@chromium.org estevenson@chromium.org -zpeng@chromium.org # COMPONENT: Build
diff --git a/build/android/bytecode/OWNERS b/build/android/bytecode/OWNERS index a512a5a..c964495 100644 --- a/build/android/bytecode/OWNERS +++ b/build/android/bytecode/OWNERS
@@ -1,5 +1,4 @@ agrieve@chromium.org estevenson@chromium.org -zpeng@chromium.org # COMPONENT: Build
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index f068835b..6beaf612 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -407,6 +407,9 @@ ImageInvalidationUpdateDurationHistogramTimer image_invalidation_timer; PaintImageIdFlatSet images_to_invalidate = tile_manager_.TakeImagesToInvalidateOnSyncTree(); + if (ukm_manager_) + ukm_manager_->AddCheckerboardedImages(images_to_invalidate.size()); + if (image_animation_controller_.has_value()) { const auto& animated_images = image_animation_controller_.value().AnimateForSyncTree(
diff --git a/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/cc/trees/layer_tree_host_unittest_checkerimaging.cc index 3a96d3b3..f71c658 100644 --- a/cc/trees/layer_tree_host_unittest_checkerimaging.cc +++ b/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -8,18 +8,40 @@ #include "cc/test/layer_tree_test.h" #include "cc/test/skia_common.h" #include "cc/trees/layer_tree_impl.h" +#include "components/ukm/test_ukm_recorder.h" #include "components/viz/test/begin_frame_args_test.h" #include "components/viz/test/fake_external_begin_frame_source.h" #include "components/viz/test/test_layer_tree_frame_sink.h" namespace cc { namespace { +const char kRenderingEvent[] = "Compositor.Rendering"; +const char kCheckerboardImagesMetric[] = "CheckerboardedImagesCount"; class LayerTreeHostCheckerImagingTest : public LayerTreeTest { public: - void BeginTest() override { PostSetNeedsCommitToMainThread(); } + LayerTreeHostCheckerImagingTest() : url_(GURL("https://example.com")) {} + + void BeginTest() override { + layer_tree_host()->SetURLForUkm(url_); + PostSetNeedsCommitToMainThread(); + } void AfterTest() override {} + void VerifyUkmAndEndTest(LayerTreeHostImpl* impl) { + // Change the URL to ensure any accumulated metrics are flushed. + impl->ukm_manager()->SetSourceURL(GURL("chrome://test2")); + + auto* recorder = static_cast<ukm::TestUkmRecorder*>( + impl->ukm_manager()->recorder_for_testing()); + const auto& entries = recorder->GetEntriesByName(kRenderingEvent); + ASSERT_EQ(1u, entries.size()); + auto* entry = entries[0]; + recorder->ExpectEntrySourceHasUrl(entry, url_); + recorder->ExpectEntryMetric(entry, kCheckerboardImagesMetric, 1); + EndTest(); + } + void InitializeSettings(LayerTreeSettings* settings) override { settings->enable_checker_imaging = true; settings->min_image_bytes_to_checker = 512 * 1024; @@ -50,6 +72,7 @@ private: // Accessed only on the main thread. FakeContentLayerClient content_layer_client_; + GURL url_; }; class LayerTreeHostCheckerImagingTestMergeWithMainFrame @@ -118,7 +141,7 @@ expected_update_rect.Union(gfx::Rect(600, 0, 50, 500)); EXPECT_EQ(sync_layer_impl->update_rect(), expected_update_rect); - EndTest(); + VerifyUkmAndEndTest(host_impl); } break; default: NOTREACHED(); @@ -182,8 +205,9 @@ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { num_of_activations_++; - if (num_of_activations_ == 2) - EndTest(); + if (num_of_activations_ == 2) { + VerifyUkmAndEndTest(host_impl); + } } void AfterTest() override {
diff --git a/cc/trees/ukm_manager.cc b/cc/trees/ukm_manager.cc index 8a817d5..cf500c92 100644 --- a/cc/trees/ukm_manager.cc +++ b/cc/trees/ukm_manager.cc
@@ -14,11 +14,15 @@ DCHECK(recorder_); } -UkmManager::~UkmManager() = default; +UkmManager::~UkmManager() { + RecordCheckerboardUkm(); + RecordRenderingUkm(); +} void UkmManager::SetSourceURL(const GURL& url) { // If we accumulating any metrics, record them before reseting the source. RecordCheckerboardUkm(); + RecordRenderingUkm(); source_id_ = recorder_->GetNewSourceID(); recorder_->UpdateSourceURL(source_id_, url); @@ -46,6 +50,14 @@ num_of_frames_++; } +void UkmManager::AddCheckerboardedImages(int num_of_checkerboarded_images) { + if (user_interaction_in_progress_) { + num_of_images_checkerboarded_during_interaction_ += + num_of_checkerboarded_images; + } + total_num_of_checkerboarded_images_ += num_of_checkerboarded_images; +} + void UkmManager::RecordCheckerboardUkm() { // Only make a recording if there was any visible area from PictureLayers, // which can be checkerboarded. @@ -57,6 +69,8 @@ .SetNumMissingTiles(num_missing_tiles_ / num_of_frames_) .SetCheckerboardedContentAreaRatio( (checkerboarded_content_area_ * 100) / total_visible_area_) + .SetCheckerboardedImagesCount( + num_of_images_checkerboarded_during_interaction_) .Record(recorder_.get()); } @@ -64,6 +78,17 @@ num_missing_tiles_ = 0; num_of_frames_ = 0; total_visible_area_ = 0; + num_of_images_checkerboarded_during_interaction_ = 0; +} + +void UkmManager::RecordRenderingUkm() { + if (source_id_ == ukm::kInvalidSourceId) + return; + + ukm::builders::Compositor_Rendering(source_id_) + .SetCheckerboardedImagesCount(total_num_of_checkerboarded_images_) + .Record(recorder_.get()); + total_num_of_checkerboarded_images_ = 0; } } // namespace cc
diff --git a/cc/trees/ukm_manager.h b/cc/trees/ukm_manager.h index 7521ccc..fef49175 100644 --- a/cc/trees/ukm_manager.h +++ b/cc/trees/ukm_manager.h
@@ -29,22 +29,30 @@ void SetSourceURL(const GURL& url); + // These metrics are recorded while a user interaction is in progress. void SetUserInteractionInProgress(bool in_progress); void AddCheckerboardStatsForFrame(int64_t checkerboard_area, int64_t num_missing_tiles, int64_t total_visible_area); + // These metrics are recorded until the source URL changes. + void AddCheckerboardedImages(int num_of_checkerboarded_images); + ukm::UkmRecorder* recorder_for_testing() { return recorder_.get(); } private: void RecordCheckerboardUkm(); + void RecordRenderingUkm(); bool user_interaction_in_progress_ = false; + int64_t num_of_images_checkerboarded_during_interaction_ = 0; int64_t checkerboarded_content_area_ = 0; int64_t num_missing_tiles_ = 0; int64_t total_visible_area_ = 0; int64_t num_of_frames_ = 0; + int total_num_of_checkerboarded_images_ = 0; + ukm::SourceId source_id_ = ukm::kInvalidSourceId; std::unique_ptr<ukm::UkmRecorder> recorder_; };
diff --git a/cc/trees/ukm_manager_unittest.cc b/cc/trees/ukm_manager_unittest.cc index f9ad62bc..f69ab61 100644 --- a/cc/trees/ukm_manager_unittest.cc +++ b/cc/trees/ukm_manager_unittest.cc
@@ -14,9 +14,12 @@ const char kTestUrl2[] = "https://example.com/bar"; const char kUserInteraction[] = "Compositor.UserInteraction"; +const char kRendering[] = "Compositor.Rendering"; + const char kCheckerboardArea[] = "CheckerboardedContentArea"; const char kCheckerboardAreaRatio[] = "CheckerboardedContentAreaRatio"; const char kMissingTiles[] = "NumMissingTiles"; +const char kCheckerboardedImagesCount[] = "CheckerboardedImagesCount"; class UkmManagerTest : public testing::Test { public: @@ -36,6 +39,7 @@ manager_->SetUserInteractionInProgress(true); manager_->AddCheckerboardStatsForFrame(5, 1, 10); manager_->AddCheckerboardStatsForFrame(15, 3, 30); + manager_->AddCheckerboardedImages(6); manager_->SetUserInteractionInProgress(false); // We should see a single entry for the interaction above. @@ -49,6 +53,7 @@ test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardArea, 10); test_ukm_recorder_->ExpectEntryMetric(entry, kMissingTiles, 2); test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 50); + test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 6); } test_ukm_recorder_->Purge(); @@ -75,6 +80,16 @@ test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardArea, 20); test_ukm_recorder_->ExpectEntryMetric(entry, kMissingTiles, 3); test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 20); + test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 0); + } + + // An entry for rendering is emitted when the URL changes. + const auto& entries_rendering = + test_ukm_recorder_->GetEntriesByName(kRendering); + EXPECT_EQ(1u, entries_rendering.size()); + for (const auto* entry : entries_rendering) { + EXPECT_EQ(original_id, entry->source_id); + test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 6); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 7dd2046..34089a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -204,6 +204,7 @@ public static final String DONT_PREFETCH_LIBRARIES = "DontPrefetchLibraries"; public static final String DOWNLOAD_HOME_SHOW_STORAGE_INFO = "DownloadHomeShowStorageInfo"; public static final String DOWNLOADS_FOREGROUND = "DownloadsForeground"; + public static final String DOWNLOADS_LOCATION_CHANGE = "DownloadsLocationChange"; // When enabled, fullscreen WebContents will be moved to a new Activity. Coming soon... public static final String FULLSCREEN_ACTIVITY = "FullscreenActivity"; public static final String GRANT_NOTIFICATIONS_TO_DSE = "GrantNotificationsToDSE";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 648062e33..6c4844f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -394,6 +394,7 @@ @Override public boolean dispatchDragEvent(DragEvent e) { + if (mTabVisible == null) return false; ContentViewCore contentViewCore = mTabVisible.getContentViewCore(); if (contentViewCore == null) return false;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index b4952242..4b98ce4 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -7527,11 +7527,11 @@ <message name="IDS_PROFILES_SYNC_SETTINGS_LINK" desc="The link text to the Chrome sync settings page in the avatar menu tutorial card."> Settings </message> - <message name="IDS_PROFILES_TURN_ON_SYNC_BUTTON" desc="Button in the profile user menu to turn on Sync."> - Turn on Sync + <message name="IDS_PROFILES_DICE_SIGNIN_BUTTON" desc="Button in the profile user menu to sign in and turn on Sync."> + Sign in </message> - <message name="IDS_PROFILES_TURN_ON_SYNC_PROMO" desc="Text describing the benefits of turning on Sync."> - Turn on Sync to get your bookmarks, history, passwords, and other settings on all your devices. + <message name="IDS_PROFILES_DICE_SIGNIN_PROMO" desc="Text describing the benefits of signing in and turning on Sync."> + Sign in for a personalized browsing experience, synced across your devices </message> <message name="IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON" desc="Text of the ok button on the account removal view in the avatar menu bubble."> Remove account
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index c428c8a..8a3a457 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3560,6 +3560,13 @@ FEATURE_VALUE_TYPE(features::kDownloadsForeground)}, #endif // defined(OS_ANDROID) +#if defined(OS_ANDROID) + {"enable-downloads-location-change", + flag_descriptions::kDownloadsLocationChangeName, + flag_descriptions::kDownloadsLocationChangeDescription, kOsAndroid, + FEATURE_VALUE_TYPE(features::kDownloadsLocationChange)}, +#endif // defined(OS_ANDROID) + {"enable-block-tab-unders", flag_descriptions::kBlockTabUndersName, flag_descriptions::kBlockTabUndersDescription, kOsAll, FEATURE_VALUE_TYPE(TabUnderNavigationThrottle::kBlockTabUnders)},
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 9912616..0fa76ec1 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -44,6 +44,7 @@ &features::kClearOldBrowsingData, &features::kCopylessPaste, &features::kDownloadsForeground, + &features::kDownloadsLocationChange, &features::kImportantSitesInCbd, &features::kMaterialDesignIncognitoNTP, &features::kServiceWorkerPaymentApps,
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc index 2270f3ee..6db3112 100644 --- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -13,11 +13,12 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" #include "content/public/browser/android/compositor.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/url_loader_factory.mojom.h" #include "jni/ContextualSearchSceneLayer_jni.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_request_context_getter.h" #include "ui/android/resources/resource_manager_impl.h" #include "ui/android/view_android.h" #include "ui/gfx/android/java_bitmap.h" @@ -193,14 +194,16 @@ GURL gurl(thumbnail_url_); Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); + content::mojom::URLLoaderFactory* loader_factory = + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess(); fetcher_ = base::MakeUnique<chrome::BitmapFetcher>(gurl, this, NO_TRAFFIC_ANNOTATION_YET); fetcher_->Init( - profile->GetRequestContext(), std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - fetcher_->Start(); + fetcher_->Start(loader_factory); } void ContextualSearchSceneLayer::OnFetchComplete(const GURL& url,
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc index af9447a2..b3c6a4a 100644 --- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc +++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
@@ -4,7 +4,9 @@ #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_status.h" @@ -20,40 +22,40 @@ BitmapFetcher::~BitmapFetcher() { } -void BitmapFetcher::Init(net::URLRequestContextGetter* request_context, - const std::string& referrer, - net::URLRequest::ReferrerPolicy referrer_policy, +void BitmapFetcher::Init(const std::string& referrer, + blink::WebReferrerPolicy referrer_policy, int load_flags) { - if (url_fetcher_ != NULL) + if (simple_loader_ != NULL) return; - url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET, this, - traffic_annotation_); - url_fetcher_->SetRequestContext(request_context); - url_fetcher_->SetReferrer(referrer); - url_fetcher_->SetReferrerPolicy(referrer_policy); - url_fetcher_->SetLoadFlags(load_flags); + auto resource_request = std::make_unique<content::ResourceRequest>(); + resource_request->url = url_; + resource_request->referrer = GURL(referrer); + resource_request->referrer_policy = referrer_policy; + resource_request->load_flags = load_flags; + simple_loader_ = content::SimpleURLLoader::Create(std::move(resource_request), + traffic_annotation_); } -void BitmapFetcher::Start() { - if (url_fetcher_) - url_fetcher_->Start(); +void BitmapFetcher::Start(content::mojom::URLLoaderFactory* loader_factory) { + if (simple_loader_) { + content::SimpleURLLoader::BodyAsStringCallback callback = base::BindOnce( + &BitmapFetcher::OnSimpleLoaderComplete, base::Unretained(this)); + simple_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + loader_factory, std::move(callback)); + } } -// Methods inherited from URLFetcherDelegate. - -void BitmapFetcher::OnURLFetchComplete(const net::URLFetcher* source) { - if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS) { +void BitmapFetcher::OnSimpleLoaderComplete( + std::unique_ptr<std::string> response_body) { + if (!response_body) { ReportFailure(); return; } - std::string image_data; - source->GetResponseAsString(&image_data); - // Call start to begin decoding. The ImageDecoder will call OnImageDecoded // with the data when it is done. - ImageDecoder::Start(this, image_data); + ImageDecoder::Start(this, *response_body); } // Methods inherited from ImageDecoder::ImageRequest.
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h index a34ef5ab..3e28b91 100644 --- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h +++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
@@ -7,27 +7,23 @@ #include <memory> +#include "base/callback_forward.h" #include "base/macros.h" #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h" #include "chrome/browser/image_decoder.h" +#include "content/public/common/resource_request.h" +#include "content/public/common/simple_url_loader.h" +#include "content/public/common/url_loader_factory.mojom.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_request.h" #include "url/gurl.h" class SkBitmap; -namespace net { -class URLFetcher; -class URLRequestContextGetter; -} // namespace net - namespace chrome { // Asynchrounously fetches an image from the given URL and returns the // decoded Bitmap to the provided BitmapFetcherDelegate. -class BitmapFetcher : public net::URLFetcherDelegate, - public ImageDecoder::ImageRequest { +class BitmapFetcher : public ImageDecoder::ImageRequest { public: BitmapFetcher(const GURL& url, BitmapFetcherDelegate* delegate, @@ -35,7 +31,6 @@ ~BitmapFetcher() override; const GURL& url() const { return url_; } - net::URLFetcher* url_fetcher() { return url_fetcher_.get(); } // Initializes internal fetcher. After this function returns url_fetcher() // can be accessed to configure it further (eg. add user data to request). @@ -43,22 +38,15 @@ // Values for |load_flags| are defined in net/base/load_flags.h. In general, // |net::LOAD_NORMAL| is appropriate. Init may be called more than once in // some cases. If so, subsequent starts will be ignored. - void Init(net::URLRequestContextGetter* request_context, - const std::string& referrer, - net::URLRequest::ReferrerPolicy referrer_policy, + void Init(const std::string& referrer, + blink::WebReferrerPolicy referrer_policy, int load_flags); // Start fetching the URL with the fetcher. The delegate is notified // asynchronously when done. Start may be called more than once in some // cases. If so, subsequent starts will be ignored since the operation is // already in progress. - void Start(); - - // Methods inherited from URLFetcherDelegate - - // This will be called when the URL has been fetched, successfully or not. - // Use accessor methods on |source| to get the results. - void OnURLFetchComplete(const net::URLFetcher* source) override; + void Start(content::mojom::URLLoaderFactory* loader_factory); // Methods inherited from ImageDecoder::ImageRequest @@ -71,10 +59,13 @@ void OnDecodeImageFailed() override; private: + void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body); + // Alerts the delegate that a failure occurred. void ReportFailure(); - std::unique_ptr<net::URLFetcher> url_fetcher_; + std::unique_ptr<content::SimpleURLLoader> simple_loader_; + const GURL url_; BitmapFetcherDelegate* const delegate_; const net::NetworkTrafficAnnotationTag traffic_annotation_;
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc index bb90df207..c9e4144 100644 --- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc +++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
@@ -10,12 +10,14 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/storage_partition.h" #include "content/public/test/test_utils.h" #include "net/base/load_flags.h" #include "net/http/http_status_code.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" -#include "net/url_request/test_url_fetcher_factory.h" -#include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_status.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -25,6 +27,13 @@ const bool kAsyncCall = true; const bool kSyncCall = false; +const char kStartTestURL[] = "/this-should-work"; +const char kOnImageDecodedTestURL[] = "/this-should-work-as-well"; +const char kOnURLFetchFailureTestURL[] = "/this-should-be-fetch-failure"; + +using net::test_server::BasicHttpResponse; +using net::test_server::HttpRequest; +using net::test_server::HttpResponse; namespace chrome { @@ -77,15 +86,53 @@ class BitmapFetcherBrowserTest : public InProcessBrowserTest { public: - void SetUp() override { - url_fetcher_factory_.reset( - new net::FakeURLFetcherFactory(&url_fetcher_impl_factory_)); - InProcessBrowserTest::SetUp(); + // InProcessBrowserTest overrides: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + + // Set up the test server. + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &BitmapFetcherBrowserTest::HandleRequest, base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + void TearDownOnMainThread() override { + // Tear down the test server. + EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); + InProcessBrowserTest::TearDownOnMainThread(); } protected: - net::URLFetcherImplFactory url_fetcher_impl_factory_; - std::unique_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_; + SkBitmap test_bitmap() const { + // Return some realistic looking bitmap data + SkBitmap image; + + // Put a real bitmap into "image". 2x2 bitmap of green 32 bit pixels. + image.allocN32Pixels(2, 2); + image.eraseColor(SK_ColorGREEN); + return image; + } + + private: + std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { + std::unique_ptr<BasicHttpResponse> response(new BasicHttpResponse); + if (request.relative_url == kStartTestURL) { + // Encode the bits as a PNG. + std::vector<unsigned char> compressed; + gfx::PNGCodec::EncodeBGRASkBitmap(test_bitmap(), true, &compressed); + // Copy the bits into a string and return them through the embedded + // test server + std::string image_string(compressed.begin(), compressed.end()); + response->set_code(net::HTTP_OK); + response->set_content(image_string); + } else if (request.relative_url == kOnImageDecodedTestURL) { + response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); + } else if (request.relative_url == kOnURLFetchFailureTestURL) { + response->set_code(net::HTTP_OK); + response->set_content(std::string("Not a real bitmap")); + } + return std::move(response); + } }; // WARNING: These tests work with --single_process, but not @@ -93,38 +140,22 @@ // for us by the test process if --single-process is used. IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, StartTest) { - GURL url("http://example.com/this-should-work"); - - // Put some realistic looking bitmap data into the url_fetcher. - SkBitmap image; - - // Put a real bitmap into "image". 2x2 bitmap of green 32 bit pixels. - image.allocN32Pixels(2, 2); - image.eraseColor(SK_ColorGREEN); - - // Encode the bits as a PNG. - std::vector<unsigned char> compressed; - ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(image, true, &compressed)); - - // Copy the bits into the string, and put them into the FakeURLFetcher. - std::string image_string(compressed.begin(), compressed.end()); + GURL url = embedded_test_server()->GetURL(kStartTestURL); // Set up a delegate to wait for the callback. BitmapFetcherTestDelegate delegate(kAsyncCall); BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS); - url_fetcher_factory_->SetFakeResponse( - url, image_string, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - // We expect that the image decoder will get called and return // an image in a callback to OnImageDecoded(). fetcher.Init( - browser()->profile()->GetRequestContext(), std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - fetcher.Start(); + fetcher.Start( + content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) + ->GetURLLoaderFactoryForBrowserProcess()); // Blocks until test delegate is notified via a callback. delegate.Wait(); @@ -133,11 +164,11 @@ // Make sure we get back the bitmap we expect. const SkBitmap& found_image = delegate.bitmap(); - EXPECT_TRUE(gfx::BitmapsAreEqual(image, found_image)); + EXPECT_TRUE(gfx::BitmapsAreEqual(test_bitmap(), found_image)); } IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, OnImageDecodedTest) { - GURL url("http://example.com/this-should-work-as-well"); + GURL url = embedded_test_server()->GetURL(kOnImageDecodedTestURL); SkBitmap image; // Put a real bitmap into "image". 2x2 bitmap of green 16 bit pixels. @@ -158,7 +189,7 @@ } IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, OnURLFetchFailureTest) { - GURL url("http://example.com/this-should-be-fetch-failure"); + GURL url = embedded_test_server()->GetURL(kOnURLFetchFailureTestURL); // We intentionally put no data into the bitmap to simulate a failure. @@ -167,17 +198,13 @@ BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS); - url_fetcher_factory_->SetFakeResponse(url, - std::string(), - net::HTTP_INTERNAL_SERVER_ERROR, - net::URLRequestStatus::FAILED); - fetcher.Init( - browser()->profile()->GetRequestContext(), std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - fetcher.Start(); + fetcher.Start( + content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) + ->GetURLLoaderFactoryForBrowserProcess()); // Blocks until test delegate is notified via a callback. delegate.Wait(); @@ -189,17 +216,14 @@ GURL url("http://example.com/this-should-be-a-decode-failure"); BitmapFetcherTestDelegate delegate(kAsyncCall); BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS); - url_fetcher_factory_->SetFakeResponse(url, - std::string("Not a real bitmap"), - net::HTTP_OK, - net::URLRequestStatus::SUCCESS); fetcher.Init( - browser()->profile()->GetRequestContext(), std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - fetcher.Start(); + fetcher.Start( + content::BrowserContext::GetDefaultStoragePartition(browser()->profile()) + ->GetURLLoaderFactoryForBrowserProcess()); // Blocks until test delegate is notified via a callback. delegate.Wait();
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc index 84aece2..1052408 100644 --- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc +++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
@@ -132,12 +132,12 @@ new chrome::BitmapFetcher(url, this, traffic_annotation)); new_fetcher->Init( - content::BrowserContext::GetDefaultStoragePartition(context_)-> - GetURLRequestContext(), std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - new_fetcher->Start(); + new_fetcher->Start( + content::BrowserContext::GetDefaultStoragePartition(context_) + ->GetURLLoaderFactoryForBrowserProcess()); return new_fetcher; }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc index a1019cc..7eca0f1 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -20,10 +20,12 @@ #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/webstore_data_fetcher.h" #include "chrome/browser/extensions/webstore_install_helper.h" +#include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "content/public/browser/browser_thread.h" +#include "content/public/common/url_loader_factory.mojom.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/image_loader.h" #include "extensions/browser/sandboxed_unpacker.h" @@ -192,14 +194,10 @@ void Start(const std::string& app_id, const std::string& manifest, const GURL& icon_url, - net::URLRequestContextGetter* context_getter) { + content::mojom::URLLoaderFactory* loader_factory) { scoped_refptr<extensions::WebstoreInstallHelper> webstore_helper = - new extensions::WebstoreInstallHelper(this, - app_id, - manifest, - icon_url, - context_getter); - webstore_helper->Start(); + new extensions::WebstoreInstallHelper(this, app_id, manifest, icon_url); + webstore_helper->Start(loader_factory); } private: @@ -369,6 +367,11 @@ return g_browser_process->system_request_context(); } +content::mojom::URLLoaderFactory* KioskAppData::GetURLLoaderFactory() { + return g_browser_process->system_network_context_manager() + ->GetURLLoaderFactory(); +} + bool KioskAppData::LoadFromCache() { PrefService* local_state = g_browser_process->local_state(); const base::DictionaryValue* dict = @@ -492,7 +495,7 @@ // WebstoreDataParser deletes itself when done. (new WebstoreDataParser(weak_factory_.GetWeakPtr())) - ->Start(app_id(), manifest, icon_url, GetRequestContextGetter()); + ->Start(app_id(), manifest, icon_url, GetURLLoaderFactory()); } void KioskAppData::OnWebstoreResponseParseFailure(const std::string& error) {
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.h b/chrome/browser/chromeos/app_mode/kiosk_app_data.h index 2baa6a7..359152f 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.h +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.h
@@ -27,6 +27,12 @@ class Image; } +namespace content { +namespace mojom { +class URLLoaderFactory; +} +} // namespace content + namespace net { class URLRequestContextGetter; } @@ -99,6 +105,9 @@ // Returns URLRequestContextGetter to use for fetching web store data. net::URLRequestContextGetter* GetRequestContextGetter(); + // Returns URLLoaderFactory to use for fetching web store data. + content::mojom::URLLoaderFactory* GetURLLoaderFactory(); + // Loads the locally cached data. Return false if there is none. bool LoadFromCache();
diff --git a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc index 97266d7..6a13f81 100644 --- a/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc +++ b/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc
@@ -74,20 +74,19 @@ } } - net::URLRequestContextGetter* context_getter = nullptr; + content::mojom::URLLoaderFactory* loader_factory = nullptr; if (!icon_url.is_empty()) { - context_getter = - content::BrowserContext::GetDefaultStoragePartition(browser_context())-> - GetURLRequestContext(); + loader_factory = + content::BrowserContext::GetDefaultStoragePartition(browser_context()) + ->GetURLLoaderFactoryForBrowserProcess(); } scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( - this, params_->details.id, params_->details.manifest, icon_url, - context_getter); + this, params_->details.id, params_->details.manifest, icon_url); // The helper will call us back via OnWebstoreParseSuccess or // OnWebstoreParseFailure. - helper->Start(); + helper->Start(loader_factory); // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure. AddRef();
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc index b6792c0..b04347d 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -218,18 +218,19 @@ ActiveInstallData install_data(details().id); scoped_active_install_.reset(new ScopedActiveInstall(tracker, install_data)); - net::URLRequestContextGetter* context_getter = nullptr; + content::mojom::URLLoaderFactory* loader_factory = nullptr; if (!icon_url.is_empty()) { - context_getter = content::BrowserContext::GetDefaultStoragePartition( - browser_context())->GetURLRequestContext(); + loader_factory = + content::BrowserContext::GetDefaultStoragePartition(browser_context()) + ->GetURLLoaderFactoryForBrowserProcess(); } scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( - this, details().id, details().manifest, icon_url, context_getter); + this, details().id, details().manifest, icon_url); // The helper will call us back via OnWebstoreParseSuccess or // OnWebstoreParseFailure. - helper->Start(); + helper->Start(loader_factory); // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure. AddRef();
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc index 8689510..b520ee4 100644 --- a/chrome/browser/extensions/webstore_install_helper.cc +++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -24,25 +24,22 @@ namespace extensions { -WebstoreInstallHelper::WebstoreInstallHelper( - Delegate* delegate, - const std::string& id, - const std::string& manifest, - const GURL& icon_url, - net::URLRequestContextGetter* context_getter) +WebstoreInstallHelper::WebstoreInstallHelper(Delegate* delegate, + const std::string& id, + const std::string& manifest, + const GURL& icon_url) : delegate_(delegate), id_(id), manifest_(manifest), icon_url_(icon_url), - context_getter_(context_getter), icon_decode_complete_(false), manifest_parse_complete_(false), - parse_error_(Delegate::UNKNOWN_ERROR) { -} + parse_error_(Delegate::UNKNOWN_ERROR) {} WebstoreInstallHelper::~WebstoreInstallHelper() {} -void WebstoreInstallHelper::Start() { +void WebstoreInstallHelper::Start( + content::mojom::URLLoaderFactory* loader_factory) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); data_decoder::SafeJsonParser::Parse( @@ -87,10 +84,10 @@ icon_fetcher_.reset( new chrome::BitmapFetcher(icon_url_, this, traffic_annotation)); icon_fetcher_->Init( - context_getter_, std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + std::string(), + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES); - icon_fetcher_->Start(); + icon_fetcher_->Start(loader_factory); } }
diff --git a/chrome/browser/extensions/webstore_install_helper.h b/chrome/browser/extensions/webstore_install_helper.h index c53ea812d..5c8342d 100644 --- a/chrome/browser/extensions/webstore_install_helper.h +++ b/chrome/browser/extensions/webstore_install_helper.h
@@ -22,9 +22,11 @@ class BitmapFetcher; } -namespace net { -class URLRequestContextGetter; +namespace content { +namespace mojom { +class URLLoaderFactory; } +} // namespace content namespace safe_json { class SafeJsonParser; @@ -69,9 +71,8 @@ WebstoreInstallHelper(Delegate* delegate, const std::string& id, const std::string& manifest, - const GURL& icon_url, - net::URLRequestContextGetter* context_getter); - void Start(); + const GURL& icon_url); + void Start(content::mojom::URLLoaderFactory* loader_factory); private: friend class base::RefCounted<WebstoreInstallHelper>; @@ -99,7 +100,6 @@ // If |icon_url_| is non-empty, it needs to be fetched and decoded into an // SkBitmap. GURL icon_url_; - net::URLRequestContextGetter* context_getter_; // Only usable on UI thread. std::unique_ptr<chrome::BitmapFetcher> icon_fetcher_; // Flags for whether we're done doing icon decoding and manifest parsing.
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc index be9e4ad..cc15d80 100644 --- a/chrome/browser/extensions/webstore_standalone_installer.cc +++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/extensions/webstore_data_fetcher.h" #include "chrome/browser/profiles/profile.h" #include "components/crx_file/id_util.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" @@ -309,14 +310,11 @@ webstore_data_ = std::move(webstore_data); scoped_refptr<WebstoreInstallHelper> helper = - new WebstoreInstallHelper(this, - id_, - manifest, - icon_url, - profile_->GetRequestContext()); + new WebstoreInstallHelper(this, id_, manifest, icon_url); // The helper will call us back via OnWebstoreParseSuccess() or // OnWebstoreParseFailure(). - helper->Start(); + helper->Start(content::BrowserContext::GetDefaultStoragePartition(profile_) + ->GetURLLoaderFactoryForBrowserProcess()); } void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 86dd5e5..a7fc91c 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1307,7 +1307,7 @@ const char kSitePerProcessName[] = "Strict site isolation"; const char kSitePerProcessDescription[] = - "Highly experimental security mode that ensures each renderer process " + "Experimental security mode that ensures each renderer process " "contains pages from at most one site. In this mode, out-of-process " "iframes will be used whenever an iframe is cross-site."; @@ -1767,6 +1767,10 @@ const char kDownloadsForegroundDescription[] = "Enable downloads as a foreground service for all versions of Android."; +const char kDownloadsLocationChangeName[] = "Enable downloads location change"; +const char kDownloadsLocationChangeDescription[] = + "Enable changing default downloads storage location on Android."; + const char kEnableAndroidPayIntegrationV1Name[] = "Enable Android Pay v1"; const char kEnableAndroidPayIntegrationV1Description[] = "Enable integration with Android Pay using the first version of the API";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 31b93f4..68ef234e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1091,6 +1091,9 @@ extern const char kDownloadsForegroundName[]; extern const char kDownloadsForegroundDescription[]; +extern const char kDownloadsLocationChangeName[]; +extern const char kDownloadsLocationChangeDescription[]; + extern const char kEnableAndroidPayIntegrationV1Name[]; extern const char kEnableAndroidPayIntegrationV1Description[];
diff --git a/chrome/browser/password_manager/account_chooser_dialog_android.cc b/chrome/browser/password_manager/account_chooser_dialog_android.cc index 837e5510..12d67b4 100644 --- a/chrome/browser/password_manager/account_chooser_dialog_android.cc +++ b/chrome/browser/password_manager/account_chooser_dialog_android.cc
@@ -23,6 +23,7 @@ #include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_ui_utils.h" #include "components/password_manager/core/common/credential_manager_types.h" +#include "content/public/browser/storage_partition.h" #include "jni/AccountChooserDialog_jni.h" #include "ui/android/window_android.h" #include "ui/base/l10n/l10n_util.h" @@ -91,13 +92,13 @@ void FetchAvatar(const base::android::ScopedJavaGlobalRef<jobject>& java_dialog, const autofill::PasswordForm* password_form, int index, - net::URLRequestContextGetter* request_context) { + content::mojom::URLLoaderFactory* loader_factory) { if (!password_form->icon_url.is_valid()) return; // Fetcher deletes itself once fetching is finished. auto* fetcher = new AvatarFetcherAndroid(password_form->icon_url, index, java_dialog); - fetcher->Start(request_context); + fetcher->Start(loader_factory); } }; // namespace @@ -148,12 +149,13 @@ title_link_range.start(), title_link_range.end(), base::android::ConvertUTF8ToJavaString(env, origin), base::android::ConvertUTF16ToJavaString(env, signin_button))); - net::URLRequestContextGetter* request_context = - Profile::FromBrowserContext(web_contents_->GetBrowserContext()) - ->GetRequestContext(); + content::mojom::URLLoaderFactory* loader_factory = + content::BrowserContext::GetDefaultStoragePartition( + Profile::FromBrowserContext(web_contents_->GetBrowserContext())) + ->GetURLLoaderFactoryForBrowserProcess(); int avatar_index = 0; for (const auto& form : local_credentials_forms()) - FetchAvatar(dialog_jobject_, form.get(), avatar_index++, request_context); + FetchAvatar(dialog_jobject_, form.get(), avatar_index++, loader_factory); } void AccountChooserDialogAndroid::OnCredentialClicked(
diff --git a/chrome/browser/profiles/profile_avatar_downloader.cc b/chrome/browser/profiles/profile_avatar_downloader.cc index a2fc1d0..9b9b50d7 100644 --- a/chrome/browser/profiles/profile_avatar_downloader.cc +++ b/chrome/browser/profiles/profile_avatar_downloader.cc
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "net/base/load_flags.h" @@ -57,16 +58,19 @@ } void ProfileAvatarDownloader::Start() { - // In unit tests, the browser process can return a NULL request context. - net::URLRequestContextGetter* request_context = - g_browser_process->system_request_context(); - if (request_context) { + SystemNetworkContextManager* system_network_context_manager = + g_browser_process->system_network_context_manager(); + // In unit tests, the browser process can return a NULL context manager + if (!system_network_context_manager) + return; + content::mojom::URLLoaderFactory* loader_factory = + system_network_context_manager->GetURLLoaderFactory(); + if (loader_factory) { fetcher_->Init( - request_context, std::string(), - net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin, net::LOAD_NORMAL); - fetcher_->Start(); + fetcher_->Start(loader_factory); } }
diff --git a/chrome/browser/resources/md_extensions/error_page.html b/chrome/browser/resources/md_extensions/error_page.html index d3fbc22..e26aab3 100644 --- a/chrome/browser/resources/md_extensions/error_page.html +++ b/chrome/browser/resources/md_extensions/error_page.html
@@ -32,6 +32,7 @@ iron-icon { --iron-icon-fill-color: var(--paper-grey-500); @apply(--cr-icon-height-width); + flex-shrink: 0; } iron-icon[icon=warning] { @@ -92,6 +93,7 @@ .error-message { -webkit-margin-start: 10px; flex-grow: 1; + word-break: break-all; } #devtools-controls {
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 29283269..4f8180fc3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -33,6 +33,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/synchronization/lock.h" #include "base/test/thread_test_helper.h" #include "base/time/time.h" #include "build/build_config.h" @@ -103,6 +104,8 @@ using ::testing::Mock; using ::testing::StrictMock; +#define ENABLE_FLAKY_PVER3_TESTS 1 + namespace safe_browsing { namespace { @@ -268,6 +271,7 @@ // Deletes the current database and creates a new one. bool ResetDatabase() override { + base::AutoLock locker(lock_); badurls_.clear(); urls_by_hash_.clear(); return true; @@ -279,6 +283,7 @@ bool ContainsBrowseUrl(const GURL& url, std::vector<SBPrefix>* prefix_hits, std::vector<SBFullHashResult>* cache_hits) override { + base::AutoLock locker(lock_); cache_hits->clear(); return ContainsUrl(MALWARE, PHISH, std::vector<GURL>(1, url), prefix_hits); } @@ -287,6 +292,7 @@ const std::vector<SBFullHash>& full_hashes, std::vector<SBPrefix>* prefix_hits, std::vector<SBFullHashResult>* cache_hits) override { + base::AutoLock locker(lock_); cache_hits->clear(); return ContainsUrl(MALWARE, PHISH, UrlsForHashes(full_hashes), prefix_hits); } @@ -295,6 +301,7 @@ const GURL& url, std::vector<SBPrefix>* prefix_hits, std::vector<SBFullHashResult>* cache_hits) override { + base::AutoLock locker(lock_); cache_hits->clear(); return ContainsUrl(UNWANTEDURL, UNWANTEDURL, std::vector<GURL>(1, url), prefix_hits); @@ -304,6 +311,7 @@ const std::vector<SBFullHash>& full_hashes, std::vector<SBPrefix>* prefix_hits, std::vector<SBFullHashResult>* cache_hits) override { + base::AutoLock locker(lock_); cache_hits->clear(); return ContainsUrl(UNWANTEDURL, UNWANTEDURL, UrlsForHashes(full_hashes), prefix_hits); @@ -312,6 +320,7 @@ bool ContainsDownloadUrlPrefixes( const std::vector<SBPrefix>& prefixes, std::vector<SBPrefix>* prefix_hits) override { + base::AutoLock locker(lock_); bool found = ContainsUrlPrefixes(BINURL, BINURL, prefixes, prefix_hits); if (!found) return false; @@ -333,6 +342,7 @@ bool ContainsResourceUrlPrefixes( const std::vector<SBPrefix>& prefixes, std::vector<SBPrefix>* prefix_hits) override { + base::AutoLock locker(lock_); prefix_hits->clear(); return ContainsUrlPrefixes(RESOURCEBLACKLIST, RESOURCEBLACKLIST, prefixes, prefix_hits); @@ -362,6 +372,7 @@ void AddUrl(const GURL& url, const SBFullHashResult& full_hash, const std::vector<SBPrefix>& prefix_hits) { + base::AutoLock locker(lock_); Hits* hits_for_url = &badurls_[url.spec()]; hits_for_url->list_ids.push_back(full_hash.list_id); hits_for_url->prefix_hits.insert(hits_for_url->prefix_hits.end(), @@ -382,6 +393,7 @@ int list_id1, const std::vector<GURL>& urls, std::vector<SBPrefix>* prefix_hits) { + lock_.AssertAcquired(); bool hit = false; for (const GURL& url : urls) { const auto badurls_it = badurls_.find(url.spec()); @@ -401,6 +413,7 @@ } std::vector<GURL> UrlsForHashes(const std::vector<SBFullHash>& full_hashes) { + lock_.AssertAcquired(); std::vector<GURL> urls; for (auto hash : full_hashes) { auto url_it = urls_by_hash_.find(SBFullHashToString(hash)); @@ -415,6 +428,7 @@ int list_id1, const std::vector<SBPrefix>& prefixes, std::vector<SBPrefix>* prefix_hits) { + lock_.AssertAcquired(); bool hit = false; for (const SBPrefix& prefix : prefixes) { for (const std::pair<int, SBPrefix>& entry : bad_prefixes_) { @@ -428,6 +442,8 @@ return hit; } + // Protects the members below. + base::Lock lock_; std::map<std::string, Hits> badurls_; std::set<std::pair<int, SBPrefix>> bad_prefixes_; std::map<std::string, GURL> urls_by_hash_; @@ -449,14 +465,46 @@ bool enable_extension_blacklist, bool enable_ip_blacklist, bool enabled_unwanted_software_list) override { + base::AutoLock locker(lock_); + db_ = new TestSafeBrowsingDatabase(); + + if (!quit_closure_.is_null()) { + quit_closure_.Run(); + quit_closure_ = base::Closure(); + } + return base::WrapUnique(db_); } - TestSafeBrowsingDatabase* GetDb() { return db_; } + + TestSafeBrowsingDatabase* GetDb() { + base::RunLoop loop; + bool should_wait = false; + { + base::AutoLock locker(lock_); + + if (db_) + return db_; + + quit_closure_ = loop.QuitClosure(); + should_wait = true; + } + + if (should_wait) + loop.Run(); + + { + base::AutoLock locker(lock_); + return db_; + } + } private: + base::Lock lock_; + // Owned by the SafebrowsingService. TestSafeBrowsingDatabase* db_; + base::Closure quit_closure_; }; // A TestProtocolManager that could return fixed responses from @@ -481,6 +529,8 @@ SafeBrowsingProtocolManager::FullHashCallback callback, bool is_download, ExtendedReportingLevel reporting_level) override { + base::AutoLock locker(lock_); + BrowserThread::PostDelayedTask( BrowserThread::IO, FROM_HERE, base::BindOnce(InvokeFullHashCallback, callback, full_hashes_), delay_); @@ -488,6 +538,7 @@ // Prepare the GetFullHash results for the next request. void AddGetFullHashResponse(const SBFullHashResult& full_hash_result) { + base::AutoLock locker(lock_); full_hashes_.push_back(full_hash_result); } @@ -498,6 +549,8 @@ static int delete_count() { return delete_count_; } private: + // Protects |full_hashes_|. + base::Lock lock_; std::vector<SBFullHashResult> full_hashes_; base::TimeDelta delay_; static int create_count_; @@ -519,15 +572,46 @@ SafeBrowsingProtocolManagerDelegate* delegate, net::URLRequestContextGetter* request_context_getter, const SafeBrowsingProtocolConfig& config) override { + base::AutoLock locker(lock_); + pm_ = new TestProtocolManager(delegate, request_context_getter, config); + + if (!quit_closure_.is_null()) { + quit_closure_.Run(); + quit_closure_ = base::Closure(); + } + return base::WrapUnique(pm_); } - TestProtocolManager* GetProtocolManager() { return pm_; } + TestProtocolManager* GetProtocolManager() { + base::RunLoop loop; + bool should_wait = false; + { + base::AutoLock locker(lock_); + + if (pm_) + return pm_; + + quit_closure_ = loop.QuitClosure(); + should_wait = true; + } + + if (should_wait) + loop.Run(); + + { + base::AutoLock locker(lock_); + return pm_; + } + } private: + base::Lock lock_; + // Owned by the SafeBrowsingService. TestProtocolManager* pm_; + base::Closure quit_closure_; }; class MockObserver : public SafeBrowsingUIManager::Observer {
diff --git a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h index 1d259661..3be32c6 100644 --- a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h +++ b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h
@@ -8,7 +8,7 @@ #include <Cocoa/Cocoa.h> #include "base/memory/ref_counted.h" -#include "net/url_request/url_request_context_getter.h" +#include "content/public/common/url_loader_factory.mojom.h" class AccountAvatarFetcherBridge; @class CredentialItemButton; @@ -17,12 +17,11 @@ // Handles retrieving avatar images for credential items. @interface AccountAvatarFetcherManager : NSObject { std::vector<std::unique_ptr<AccountAvatarFetcherBridge>> bridges_; - scoped_refptr<net::URLRequestContextGetter> requestContext_; + content::mojom::URLLoaderFactory* loaderFactory_; } -// Initializes a manager with the specified request context. -- (id)initWithRequestContext: - (scoped_refptr<net::URLRequestContextGetter>)requestContext; +// Initializes a manager with the specified URL loader factory. +- (id)initWithLoaderFactory:(content::mojom::URLLoaderFactory*)loaderFactory; // Retrieves the image located at |avatarURL| and updates |view| if successful. - (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemButton*)view;
diff --git a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm index 2667a12..26a40209 100644 --- a/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm +++ b/chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.mm
@@ -54,16 +54,15 @@ @implementation AccountAvatarFetcherManager -- (id)initWithRequestContext: - (scoped_refptr<net::URLRequestContextGetter>)requestContext { +- (id)initWithLoaderFactory:(content::mojom::URLLoaderFactory*)loaderFactory { if ((self = [super init])) { - requestContext_ = requestContext; + loaderFactory_ = loaderFactory; } return self; } - (void)startRequestWithFetcher:(AccountAvatarFetcher*)fetcher { - fetcher->Start(requestContext_.get()); + fetcher->Start(loaderFactory_); } - (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemButton*)view {
diff --git a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.mm b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.mm index bbe5d4f..0e9f263 100644 --- a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.mm
@@ -55,7 +55,7 @@ - (instancetype)initWithBridge:(PasswordPromptBridgeInterface*)bridge { base::scoped_nsobject<AccountAvatarFetcherManager> avatarManager( [[AccountAvatarFetcherManager alloc] - initWithRequestContext:bridge->GetRequestContext()]); + initWithLoaderFactory:bridge->GetURLLoaderFactory()]); return [self initWithBridge:bridge avatarManager:avatarManager]; }
diff --git a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm index 3e3b54f4..fa3a70c 100644 --- a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm
@@ -82,7 +82,7 @@ // PasswordPromptBridgeInterface: void PerformClose() override; PasswordDialogController* GetDialogController() override; - net::URLRequestContextGetter* GetRequestContext() const override; + content::mojom::URLLoaderFactory* GetURLLoaderFactory() const override; private: PasswordDialogControllerMock dialog_controller_; @@ -121,8 +121,8 @@ return &dialog_controller_; } -net::URLRequestContextGetter* -AccountChooserViewControllerTest::GetRequestContext() const { +content::mojom::URLLoaderFactory* +AccountChooserViewControllerTest::GetURLLoaderFactory() const { NOTREACHED(); return nullptr; }
diff --git a/chrome/browser/ui/cocoa/passwords/auto_signin_view_controller.mm b/chrome/browser/ui/cocoa/passwords/auto_signin_view_controller.mm index 60f79f09..961020c6 100644 --- a/chrome/browser/ui/cocoa/passwords/auto_signin_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/auto_signin_view_controller.mm
@@ -18,6 +18,8 @@ #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/url_loader_factory.mojom.h" #include "skia/ext/skia_utils_mac.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -41,10 +43,12 @@ - (instancetype)initWithDelegate: (id<BasePasswordsContentViewDelegate>)delegate { - auto* request_context = delegate.model->GetProfile()->GetRequestContext(); + auto* loader_factory = content::BrowserContext::GetDefaultStoragePartition( + delegate.model->GetProfile()) + ->GetURLLoaderFactoryForBrowserProcess(); base::scoped_nsobject<AccountAvatarFetcherManager> avatarManager( [[AccountAvatarFetcherManager alloc] - initWithRequestContext:request_context]); + initWithLoaderFactory:loader_factory]); return [self initWithAvatarManager:avatarManager delegate:delegate]; }
diff --git a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm index c46ef8f..63bba56 100644 --- a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm
@@ -41,7 +41,7 @@ // PasswordPromptBridgeInterface: void PerformClose() override; PasswordDialogController* GetDialogController() override; - net::URLRequestContextGetter* GetRequestContext() const override; + content::mojom::URLLoaderFactory* GetURLLoaderFactory() const override; private: PasswordDialogControllerMock dialog_controller_; @@ -70,8 +70,8 @@ return &dialog_controller_; } -net::URLRequestContextGetter* -AutoSigninPromptViewControllerTest::GetRequestContext() const { +content::mojom::URLLoaderFactory* +AutoSigninPromptViewControllerTest::GetURLLoaderFactory() const { NOTREACHED(); return nullptr; }
diff --git a/chrome/browser/ui/cocoa/passwords/password_prompt_bridge_interface.h b/chrome/browser/ui/cocoa/passwords/password_prompt_bridge_interface.h index 579a9e8..bc2cc86 100644 --- a/chrome/browser/ui/cocoa/passwords/password_prompt_bridge_interface.h +++ b/chrome/browser/ui/cocoa/passwords/password_prompt_bridge_interface.h
@@ -6,8 +6,10 @@ #define CHROME_BROWSER_UI_COCOA_PASSWORDS_PASSWORD_PROMPT_BRIDGE_INTERFACE_H_ class PasswordDialogController; -namespace net { -class URLRequestContextGetter; +namespace content { +namespace mojom { +class URLLoaderFactory; +} } // An interface for the bridge between AccountChooserViewController and platform @@ -20,8 +22,8 @@ // Returns the controller containing the data. virtual PasswordDialogController* GetDialogController() = 0; - // Returns the request context for fetching the avatars. - virtual net::URLRequestContextGetter* GetRequestContext() const = 0; + // Returns the URL loader factory for fetching the avatars. + virtual content::mojom::URLLoaderFactory* GetURLLoaderFactory() const = 0; protected: virtual ~PasswordPromptBridgeInterface() = default;
diff --git a/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.h b/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.h index b373110..a936f77 100644 --- a/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.h +++ b/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.h
@@ -36,7 +36,7 @@ // PasswordPromptBridgeInterface: void PerformClose() override; PasswordDialogController* GetDialogController() override; - net::URLRequestContextGetter* GetRequestContext() const override; + content::mojom::URLLoaderFactory* GetURLLoaderFactory() const override; private: void ShowWindow();
diff --git a/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.mm index be9929d6e..392f776 100644 --- a/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.mm +++ b/chrome/browser/ui/cocoa/passwords/password_prompt_view_bridge.mm
@@ -10,7 +10,9 @@ #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h" #import "chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.h" #include "chrome/browser/ui/passwords/password_dialog_controller.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/url_loader_factory.mojom.h" PasswordPromptViewBridge::PasswordPromptViewBridge( PasswordDialogController* controller, @@ -56,10 +58,11 @@ return controller_; } -net::URLRequestContextGetter* -PasswordPromptViewBridge::GetRequestContext() const { - return Profile::FromBrowserContext(web_contents_->GetBrowserContext())-> - GetRequestContext(); +content::mojom::URLLoaderFactory* +PasswordPromptViewBridge::GetURLLoaderFactory() const { + return content::BrowserContext::GetDefaultStoragePartition( + Profile::FromBrowserContext(web_contents_->GetBrowserContext())) + ->GetURLLoaderFactoryForBrowserProcess(); } void PasswordPromptViewBridge::ShowWindow() { @@ -82,4 +85,3 @@ PasswordDialogController* controller, content::WebContents* web_contents) { return new PasswordPromptViewBridge(controller, web_contents); } -
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.cc b/chrome/browser/ui/passwords/account_avatar_fetcher.cc index 958b666..a07a3ca 100644 --- a/chrome/browser/ui/passwords/account_avatar_fetcher.cc +++ b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
@@ -53,12 +53,12 @@ AccountAvatarFetcher::~AccountAvatarFetcher() = default; void AccountAvatarFetcher::Start( - net::URLRequestContextGetter* request_context) { - fetcher_.Init(request_context, std::string(), - net::URLRequest::NEVER_CLEAR_REFERRER, + content::mojom::URLLoaderFactory* loader_factory) { + fetcher_.Init(std::string(), blink::kWebReferrerPolicyAlways, net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_AUTH_DATA | net::LOAD_MAYBE_USER_GESTURE); - fetcher_.Start(); + net::LOAD_DO_NOT_SEND_AUTH_DATA | + net::LOAD_MAYBE_USER_GESTURE); + fetcher_.Start(loader_factory); } void AccountAvatarFetcher::OnFetchComplete(const GURL& /*url*/,
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.h b/chrome/browser/ui/passwords/account_avatar_fetcher.h index 09b7f40..3dae0a94 100644 --- a/chrome/browser/ui/passwords/account_avatar_fetcher.h +++ b/chrome/browser/ui/passwords/account_avatar_fetcher.h
@@ -10,14 +10,16 @@ #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" #include "url/gurl.h" +namespace content { +namespace mojom { +class URLLoaderFactory; +} +} // namespace content + namespace gfx { class ImageSkia; } // namespace gfx -namespace net { -class URLRequestContextGetter; -} // namespace net - class AccountAvatarFetcherDelegate { public: virtual void UpdateAvatar(const gfx::ImageSkia& image) = 0; @@ -33,7 +35,7 @@ ~AccountAvatarFetcher() override; - void Start(net::URLRequestContextGetter* request_context); + void Start(content::mojom::URLLoaderFactory* loader_factory); private: // chrome::BitmapFetcherDelegate:
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc index c6388319..53de1ca6 100644 --- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc +++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -14,6 +14,7 @@ #include "chrome/grit/generated_resources.h" #include "components/autofill/core/common/password_form.h" #include "components/constrained_window/constrained_window_views.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -51,7 +52,7 @@ views::ScrollView* CreateCredentialsView( const PasswordDialogController::FormsVector& forms, views::ButtonListener* button_listener, - net::URLRequestContextGetter* request_context) { + content::mojom::URLLoaderFactory* loader_factory) { views::View* list_view = new views::View; list_view->SetLayoutManager( new views::BoxLayout(views::BoxLayout::kVertical)); @@ -59,9 +60,9 @@ for (const auto& form : forms) { std::pair<base::string16, base::string16> titles = GetCredentialLabelsForAccountChooser(*form); - CredentialsItemView* credential_view = new CredentialsItemView( - button_listener, titles.first, titles.second, kButtonHoverColor, - form.get(), request_context); + CredentialsItemView* credential_view = + new CredentialsItemView(button_listener, titles.first, titles.second, + kButtonHoverColor, form.get(), loader_factory); credential_view->SetLowerLabelColor(kAutoSigninTextColor); ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get(); gfx::Insets insets = @@ -178,9 +179,11 @@ void AccountChooserDialogView::InitWindow() { SetLayoutManager(new views::FillLayout()); - AddChildView(CreateCredentialsView( - controller_->GetLocalForms(), this, - GetProfileFromWebContents(web_contents_)->GetRequestContext())); + AddChildView( + CreateCredentialsView(controller_->GetLocalForms(), this, + content::BrowserContext::GetDefaultStoragePartition( + GetProfileFromWebContents(web_contents_)) + ->GetURLLoaderFactoryForBrowserProcess())); } AccountChooserPrompt* CreateAccountChooserPromptView(
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc index 1f255ca0..a4d91a64 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.cc +++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -62,7 +62,7 @@ const base::string16& lower_text, SkColor hover_color, const autofill::PasswordForm* form, - net::URLRequestContextGetter* request_context) + content::mojom::URLLoaderFactory* loader_factory) : Button(button_listener), form_(form), upper_label_(nullptr), @@ -84,7 +84,7 @@ // Fetch the actual avatar. AccountAvatarFetcher* fetcher = new AccountAvatarFetcher( form_->icon_url, weak_ptr_factory_.GetWeakPtr()); - fetcher->Start(request_context); + fetcher->Start(loader_factory); } AddChildView(image_view_);
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.h b/chrome/browser/ui/views/passwords/credentials_item_view.h index 8aeda91..877dcb00 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.h +++ b/chrome/browser/ui/views/passwords/credentials_item_view.h
@@ -14,14 +14,16 @@ struct PasswordForm; } +namespace content { +namespace mojom { +class URLLoaderFactory; +} +} // namespace content + namespace gfx { class ImageSkia; } -namespace net { -class URLRequestContextGetter; -} - namespace views { class ImageView; class Label; @@ -37,7 +39,7 @@ const base::string16& lower_text, SkColor hover_color, const autofill::PasswordForm* form, - net::URLRequestContextGetter* request_context); + content::mojom::URLLoaderFactory* loader_factory); ~CredentialsItemView() override; const autofill::PasswordForm* form() const { return form_; }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc index ead7b543..e7125411 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -27,6 +27,7 @@ #include "chrome/grit/theme_resources.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/strings/grit/components_strings.h" +#include "content/public/browser/storage_partition.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/models/combobox_model.h" @@ -394,7 +395,9 @@ } credential = new CredentialsItemView( this, upper_text, lower_text, kButtonHoverColor, &form, - parent_->model()->GetProfile()->GetRequestContext()); + content::BrowserContext::GetDefaultStoragePartition( + parent_->model()->GetProfile()) + ->GetURLLoaderFactoryForBrowserProcess()); credential->SetEnabled(false); AddChildView(credential);
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc index 30e1687..3caff75 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
@@ -26,11 +26,16 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/content_features.h" -#include "net/url_request/test_url_fetcher_factory.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/base/ui_base_features.h" #include "ui/base/ui_features.h" +using net::test_server::BasicHttpResponse; +using net::test_server::HttpRequest; +using net::test_server::HttpResponse; using testing::Eq; using testing::Field; using testing::_; @@ -39,23 +44,6 @@ const char kDisplayDispositionMetric[] = "PasswordBubble.DisplayDisposition"; -// A helper class that will create FakeURLFetcher and record the requested URLs. -class TestURLFetcherCallback { - public: - std::unique_ptr<net::FakeURLFetcher> CreateURLFetcher( - const GURL& url, - net::URLFetcherDelegate* d, - const std::string& response_data, - net::HttpStatusCode response_code, - net::URLRequestStatus::Status status) { - OnRequestDone(url); - return std::unique_ptr<net::FakeURLFetcher>( - new net::FakeURLFetcher(url, d, response_data, response_code, status)); - } - - MOCK_METHOD1(OnRequestDone, void(const GURL&)); -}; - bool IsBubbleShowing() { return ManagePasswordsBubbleView::manage_password_bubble() && ManagePasswordsBubbleView::manage_password_bubble()-> @@ -81,6 +69,17 @@ ManagePasswordsTest::SetUp(); } + MOCK_METHOD0(OnIconRequestDone, void()); + + // Called on the server background thread. + std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { + std::unique_ptr<BasicHttpResponse> response(new BasicHttpResponse); + if (request.relative_url == "/icon.png") { + OnIconRequestDone(); + } + return std::move(response); + } + private: base::test::ScopedFeatureList scoped_feature_list_; @@ -349,24 +348,21 @@ } IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, AutoSignin) { + // Set up the test server to handle the form icon request. + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &ManagePasswordsBubbleViewTest::HandleRequest, base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); test_form()->origin = GURL("https://example.com"); test_form()->display_name = base::ASCIIToUTF16("Peter"); test_form()->username_value = base::ASCIIToUTF16("pet12@gmail.com"); - GURL icon_url("https://google.com/icon.png"); - test_form()->icon_url = icon_url; + test_form()->icon_url = embedded_test_server()->GetURL("/icon.png"); std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials; local_credentials.push_back( base::MakeUnique<autofill::PasswordForm>(*test_form())); // Prepare to capture the network request. - TestURLFetcherCallback url_callback; - net::FakeURLFetcherFactory factory( - NULL, - base::Bind(&TestURLFetcherCallback::CreateURLFetcher, - base::Unretained(&url_callback))); - factory.SetFakeResponse(icon_url, std::string(), net::HTTP_OK, - net::URLRequestStatus::FAILED); - EXPECT_CALL(url_callback, OnRequestDone(icon_url)); + EXPECT_CALL(*this, OnIconRequestDone()); + embedded_test_server()->StartAcceptingConnections(); SetupAutoSignin(std::move(local_credentials)); EXPECT_TRUE(IsBubbleShowing());
diff --git a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc index baa4f0e..414d8fa 100644 --- a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
@@ -19,32 +19,20 @@ #include "components/password_manager/core/browser/password_bubble_experiment.h" #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" -#include "net/url_request/test_url_fetcher_factory.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/views/test/widget_test.h" #include "ui/views/widget/widget.h" using ::testing::Field; +using net::test_server::BasicHttpResponse; +using net::test_server::HttpRequest; +using net::test_server::HttpResponse; namespace { -// A helper class that will create FakeURLFetcher and record the requested URLs. -class TestURLFetcherCallback { - public: - std::unique_ptr<net::FakeURLFetcher> CreateURLFetcher( - const GURL& url, - net::URLFetcherDelegate* d, - const std::string& response_data, - net::HttpStatusCode response_code, - net::URLRequestStatus::Status status) { - OnRequestDone(url); - return std::unique_ptr<net::FakeURLFetcher>( - new net::FakeURLFetcher(url, d, response_data, response_code, status)); - } - - MOCK_METHOD1(OnRequestDone, void(const GURL&)); -}; - // ManagePasswordsUIController subclass to capture the dialog instance class TestManagePasswordsUIController : public ManagePasswordsUIController { public: @@ -127,6 +115,16 @@ } MOCK_METHOD1(OnChooseCredential, void(const autofill::PasswordForm*)); + MOCK_METHOD0(OnIconRequestDone, void()); + + // Called on the server background thread. + std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { + std::unique_ptr<BasicHttpResponse> response(new BasicHttpResponse); + if (request.relative_url == "/icon.png") { + OnIconRequestDone(); + } + return std::move(response); + } private: TestManagePasswordsUIController* controller_; @@ -172,6 +170,10 @@ IN_PROC_BROWSER_TEST_F(PasswordDialogViewTest, PopupAccountChooserWithMultipleCredentialsReturnEmpty) { + // Set up the test server to handle the form icon request. + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &PasswordDialogViewTest::HandleRequest, base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); GURL origin("https://example.com"); std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials; autofill::PasswordForm form; @@ -180,21 +182,15 @@ form.username_value = base::ASCIIToUTF16("peter@pan.test"); form.icon_url = GURL("broken url"); local_credentials.push_back(base::MakeUnique<autofill::PasswordForm>(form)); - GURL icon_url("https://google.com/icon.png"); - form.icon_url = icon_url; + form.icon_url = embedded_test_server()->GetURL("/icon.png"); form.display_name = base::ASCIIToUTF16("Peter Pan"); form.federation_origin = url::Origin::Create(GURL("https://google.com/federation")); local_credentials.push_back(base::MakeUnique<autofill::PasswordForm>(form)); // Prepare to capture the network request. - TestURLFetcherCallback url_callback; - net::FakeURLFetcherFactory factory( - nullptr, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, - base::Unretained(&url_callback))); - factory.SetFakeResponse(icon_url, std::string(), net::HTTP_OK, - net::URLRequestStatus::FAILED); - EXPECT_CALL(url_callback, OnRequestDone(icon_url)); + EXPECT_CALL(*this, OnIconRequestDone()); + embedded_test_server()->StartAcceptingConnections(); SetupChooseCredentials(std::move(local_credentials), origin); ASSERT_TRUE(controller()->current_account_chooser());
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc index 2d9f183..933da78 100644 --- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -887,7 +887,7 @@ bool is_guest) { if (!avatar_item.signed_in && signin::IsDiceEnabledForProfile(browser_->profile()->GetPrefs())) - return CreateDiceTurnOnSyncView(); + return CreateDiceSigninView(); ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); @@ -989,7 +989,7 @@ return view; } -views::View* ProfileChooserView::CreateDiceTurnOnSyncView() { +views::View* ProfileChooserView::CreateDiceSigninView() { // Creates a view that holds an illustration and a promo, which includes a // button. The illustration should slightly overlap with the promo at the // bottom, therefore between_child_spacing of |view| is set to negative @@ -1013,7 +1013,7 @@ gfx::Insets(0, kMenuEdgeMargin, kMenuEdgeMargin, kMenuEdgeMargin), kMenuEdgeMargin)); views::Label* promo = new views::Label( - l10n_util::GetStringUTF16(IDS_PROFILES_TURN_ON_SYNC_PROMO)); + l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_PROMO)); promo->SetMultiLine(true); promo->SetHorizontalAlignment(gfx::ALIGN_LEFT); promo->SetMaximumWidth(menu_width_ - 2 * kMenuEdgeMargin); @@ -1021,7 +1021,7 @@ signin_current_profile_button_ = views::MdTextButton::CreateSecondaryUiBlueButton( - this, l10n_util::GetStringUTF16(IDS_PROFILES_TURN_ON_SYNC_BUTTON)); + this, l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON)); promo_button_view->AddChildView(signin_current_profile_button_); view->AddChildView(promo_button_view); return view;
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.h b/chrome/browser/ui/views/profiles/profile_chooser_view.h index e0f96d9..23a1029 100644 --- a/chrome/browser/ui/views/profiles/profile_chooser_view.h +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.h
@@ -149,9 +149,9 @@ bool reauth_required, int width); - // Creates the DICE UI view to turn on sync. It includes an illustration, a - // promo and a button. - views::View* CreateDiceTurnOnSyncView(); + // Creates the DICE UI view to sign in and turn on sync. It includes an + // illustration, a promo and a button. + views::View* CreateDiceSigninView(); // Creates a view to confirm account removal for |account_id_to_remove_|. views::View* CreateAccountRemovalView();
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc index e761bea..d19dc51 100644 --- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc
@@ -33,6 +33,10 @@ content::WebUIDataSource* html_source, Profile* profile) { EasyUnlockService* easy_unlock_service = EasyUnlockService::Get(profile); + // The service is not created for LockScreenApp profiles or "off the record". + if (!easy_unlock_service) + return nullptr; + bool allowed = easy_unlock_service->IsAllowed(); html_source->AddBoolean("easyUnlockAllowed", allowed); html_source->AddBoolean("easyUnlockEnabled",
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc index d56e735..c1e69fd 100644 --- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc
@@ -100,6 +100,11 @@ Profile::FromBrowserContext(context)); } +std::unique_ptr<KeyedService> CreateNullEasyUnlockServiceForTest( + content::BrowserContext* context) { + return nullptr; +} + } // namespace class EasyUnlockSettingsHandlerTest : public testing::Test { @@ -120,6 +125,13 @@ EasyUnlockService::Get(profile_.get())); } + void MakeEasyUnlockServiceNull() { + TestingProfile::Builder builder; + builder.AddTestingFactory(EasyUnlockServiceFactory::GetInstance(), + &CreateNullEasyUnlockServiceForTest); + profile_ = builder.Build(); + } + void VerifyEnabledStatusCallback(size_t expected_total_calls, bool expected_status) { std::string event; @@ -191,6 +203,16 @@ EXPECT_FALSE(handler.get()); } +TEST_F(EasyUnlockSettingsHandlerTest, NotCreatedWhenEasyUnlockServiceNull) { + MakeEasyUnlockServiceNull(); + std::unique_ptr<EasyUnlockSettingsHandler> handler; + content::WebUIDataSource* data_source = + content::WebUIDataSource::Create("test-data-source"); + content::WebUIDataSource::Add(profile(), data_source); + handler.reset(EasyUnlockSettingsHandler::Create(data_source, profile())); + EXPECT_FALSE(handler.get()); +} + TEST_F(EasyUnlockSettingsHandlerTest, EnabledStatus) { std::unique_ptr<EasyUnlockSettingsHandler> handler; handler.reset(new TestEasyUnlockSettingsHandler(profile()));
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index be0af73..58fe4a7e 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -199,6 +199,12 @@ base::FEATURE_ENABLED_BY_DEFAULT}; #endif +#if defined(OS_ANDROID) +// Enable changing default downloads storage location on Android. +const base::Feature kDownloadsLocationChange{"DownloadsLocationChange", + base::FEATURE_DISABLED_BY_DEFAULT}; +#endif + // Enables Expect CT reporting, which sends reports for opted-in sites // that don't serve sufficient Certificate Transparency information. const base::Feature kExpectCTReporting{"ExpectCTReporting",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 891d564..c6705685 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -105,6 +105,10 @@ extern const base::Feature kDownloadsForeground; #endif +#if defined(OS_ANDROID) +extern const base::Feature kDownloadsLocationChange; +#endif + extern const base::Feature kExpectCTReporting; extern const base::Feature kExperimentalAppBanners;
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc index eb1553b..98926f17 100644 --- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc +++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -88,6 +88,10 @@ called_field_change_ = true; } + void TextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override {} + void QueryFormFieldAutofill(int32_t id, const FormData& form, const FormFieldData& field,
diff --git a/chrome/renderer/autofill/form_autocomplete_browsertest.cc b/chrome/renderer/autofill/form_autocomplete_browsertest.cc index b77136e..6ce4f32 100644 --- a/chrome/renderer/autofill/form_autocomplete_browsertest.cc +++ b/chrome/renderer/autofill/form_autocomplete_browsertest.cc
@@ -66,6 +66,10 @@ const gfx::RectF& bounding_box, base::TimeTicks timestamp) override {} + void TextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override {} + void QueryFormFieldAutofill(int32_t id, const FormData& form, const FormFieldData& field,
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index a028701..c751e6a 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -152,7 +152,7 @@ elif chrome_binary: options['binary'] = chrome_binary - if sys.platform.startswith('linux') and not util.Is64Bit(): + if sys.platform.startswith('linux'): if chrome_switches is None: chrome_switches = [] # Workaround for crbug.com/611886.
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index b737f36..abef2ed 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -87,6 +87,8 @@ 'MobileEmulationCapabilityTest.testDeviceName', 'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabs', 'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabsImmediately', + # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2164 + 'ChromeDriverTest.testSendTextToAlert', ] _VERSION_SPECIFIC_FILTER['64'] = [
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index a6768ea..4a93fd3 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -375,6 +375,7 @@ test_type = "junit" tests = [ "//base:base_junit_tests", + "//chromecast/base:cast_base_junit_tests", "//chromecast/browser/android:cast_shell_junit_tests", "//content/public/android:content_junit_tests", "//net/android:net_junit_tests",
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn index 29db389..0dfcb1e 100644 --- a/chromecast/base/BUILD.gn +++ b/chromecast/base/BUILD.gn
@@ -269,6 +269,7 @@ java_files = [ "$java_src_dir/org/chromium/chromecast/base/CastSettingsManager.java", "$java_src_dir/org/chromium/chromecast/base/ChromecastConfigAndroid.java", + "$java_src_dir/org/chromium/chromecast/base/CircularBuffer.java", "$java_src_dir/org/chromium/chromecast/base/DumpstateWriter.java", "$java_src_dir/org/chromium/chromecast/base/SystemTimeChangeNotifierAndroid.java", ] @@ -277,4 +278,15 @@ "//base:base_java", ] } + + junit_binary("cast_base_junit_tests") { + java_test_dir = "//chromecast/base/java/test" + java_files = [ + "$java_test_dir/org/chromium/chromecast/base/CircularBufferTest.java", + ] + deps = [ + ":base_java", + "//third_party/hamcrest:hamcrest_java", + ] + } }
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java b/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java new file mode 100644 index 0000000..8e0c33d --- /dev/null +++ b/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java
@@ -0,0 +1,78 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chromecast.base; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * An Iterable object that stores up to a fixed amount of objects, and overwrites the least-recently + * inserted object if it exceeds its capacity. Appending, removing, and iterating are all constant + * time. + * + * This class is intended as a fast Iterable Deque with a fixed capacity. LinkedList generates lint + * warnings because every item requires a heap allocation for the Node, ArrayList requires rewriting + * the list when the head is removed, and ArrayDeque is not fixed-size. + * + * Currently, the only supported use case is appending items to the buffer, and then iterating the + * buffer. Concurrent modification while iterating, or appending items after iterating, is + * undefined behavior as of now. + * + * @param <T> The type that elements of the buffer should be instances of. + */ +public class CircularBuffer<T> implements Iterable<T> { + private final List<T> mData; + private final int mSize; + private boolean mAtCapacity; + private int mHeadPosition; + private int mTailPosition; + + public CircularBuffer(int size) { + mData = new ArrayList<T>(size); + mSize = size; + mAtCapacity = false; + mHeadPosition = 0; + mTailPosition = 0; + } + + public void add(T item) { + if (mSize == 0) { + return; + } + if (mAtCapacity) { + mData.set(mHeadPosition, item); + mHeadPosition = increment(mHeadPosition); + } else { + mData.add(item); + } + mTailPosition = increment(mTailPosition); + if (mTailPosition == mHeadPosition) { + mAtCapacity = true; + } + } + + @Override + public Iterator<T> iterator() { + return new Iterator<T>() { + @Override + public boolean hasNext() { + return mAtCapacity || mHeadPosition != mTailPosition; + } + + @Override + public T next() { + T result = mData.get(mHeadPosition); + mHeadPosition = increment(mHeadPosition); + mAtCapacity = false; + return result; + } + }; + } + + private int increment(int position) { + return (position + 1) % mSize; + } +}
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java new file mode 100644 index 0000000..ec52b9b --- /dev/null +++ b/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chromecast.base; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.emptyIterable; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * Tests for CircularBuffer. + * + * Currently, the only supported use case is appending items to the buffer, and then iterating the + * buffer. Concurrent modification while iterating, or appending items after iterating, is + * undefined behavior as of now. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class CircularBufferTest { + @Test + public void testBufferWithNoCapacity() { + CircularBuffer<String> buffer = new CircularBuffer<>(0); + buffer.add("a"); + assertThat(buffer, emptyIterable()); + } + + @Test + public void testBufferWithPartialCapacity() { + CircularBuffer<String> buffer = new CircularBuffer<>(4); + buffer.add("a"); + buffer.add("b"); + buffer.add("c"); + assertThat(buffer, contains("a", "b", "c")); + } + + @Test + public void testBufferWithFullCapacity() { + CircularBuffer<String> buffer = new CircularBuffer<>(4); + buffer.add("zero"); + buffer.add("one"); + buffer.add("two"); + buffer.add("three"); + assertThat(buffer, contains("zero", "one", "two", "three")); + } + + @Test + public void testBufferThatOverflowsCapacityWrapsAroundAndErasesOldestElements() { + CircularBuffer<String> buffer = new CircularBuffer<>(4); + buffer.add("1"); + buffer.add("2"); + buffer.add("3"); + buffer.add("4"); // Hits capacity; subsequent additions overwrite oldest elements. + buffer.add("5"); // erases "1" + buffer.add("6"); // erases "2" + assertThat(buffer, contains("3", "4", "5", "6")); + } + + @Test + public void testBufferThatOverflowsTwice() { + CircularBuffer<String> buffer = new CircularBuffer<>(2); + buffer.add("a"); + buffer.add("b"); + buffer.add("c"); + buffer.add("d"); + buffer.add("e"); + // Since the capacity is 2, return the 2 most-recently added items. + assertThat(buffer, contains("d", "e")); + } +}
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn index 9374666d..54077e51 100644 --- a/chromecast/browser/android/BUILD.gn +++ b/chromecast/browser/android/BUILD.gn
@@ -11,9 +11,8 @@ cast_shell_android_manifest = "$root_gen_dir/cast_shell_manifest/AndroidManifest.xml" -manifest_variables = [ - "cast_build_enable_background_activities=$enable_background_activities", -] +manifest_variables = + [ "cast_build_enable_background_activities=$enable_background_activities" ] jinja_template("cast_shell_manifest") { input = "apk/AndroidManifest.xml.jinja2" @@ -69,6 +68,7 @@ "$java_src_dir/org/chromium/chromecast/shell/CastWebContentsActivity.java", "$java_src_dir/org/chromium/chromecast/shell/CastWebContentsService.java", "$java_src_dir/org/chromium/chromecast/shell/CastWebContentsComponent.java", + "$java_src_dir/org/chromium/chromecast/shell/LogcatElision.java", "$java_src_dir/org/chromium/chromecast/shell/LogcatExtractor.java", ] @@ -102,6 +102,7 @@ junit_binary("cast_shell_junit_tests") { java_files = [ "junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java", + "junit/src/org/chromium/chromecast/shell/LogcatElisionUnitTest.java", "junit/src/org/chromium/chromecast/shell/LogcatExtractorUnitTest.java", ] @@ -113,5 +114,6 @@ "//base:base_java_test_support", "//content/public/android:content_java", "//third_party/android_tools:android_support_core_utils_java", + "//third_party/hamcrest:hamcrest_java", ] }
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatElision.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatElision.java new file mode 100644 index 0000000..596e10f --- /dev/null +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatElision.java
@@ -0,0 +1,179 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chromecast.shell; + +import android.util.Patterns; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class LogcatElision { + private static final String EMAIL_ELISION = "<EMAIL-ELIDED>"; + private static final String URL_ELISION = "<WEBADDRESS-ELIDED>"; + + private static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; + + private static final Pattern IP_ADDRESS = Pattern.compile( + "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + + "|[1-9][0-9]|[0-9]))"); + + private static final String IRI = + "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}"; + + private static final String GOOD_GTLD_CHAR = "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; + private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}"; + private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD; + + private static final Pattern DOMAIN_NAME = + Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")"); + + private static final Pattern WEB_URL = + Pattern.compile("(?:\\b|^)((?:(http|https|Http|Https|rtsp|Rtsp):" + + "\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" + + "(?:" + DOMAIN_NAME + ")" + + "(?:\\:\\d{1,5})?)" + + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" + + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" + + "(?:\\b|$)"); + + private static final String IP_ELISION = "<IP-ELIDED>"; + private static final String MAC_ELISION = "<MAC-ELIDED>"; + + private static final String CONSOLE_ELISION = "[ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE"; + + private static final Pattern MAC_ADDRESS = + Pattern.compile("([0-9a-fA-F]{2}[-:]+){5}[0-9a-fA-F]{2}"); + private static final Pattern CONSOLE_MSG = Pattern.compile("\\[\\w*:CONSOLE.*\\].*"); + + private static final String[] CHROME_NAMESPACE = new String[] {"org.chromium.", "com.google."}; + + private static final String[] CAST_NAMESPACE = new String[] {"Cast.", "CastV2."}; + + private static final String[] SYSTEM_NAMESPACE = new String[] {"android.accessibilityservice", + "android.accounts", "android.animation", "android.annotation", "android.app", + "android.appwidget", "android.bluetooth", "android.content", "android.database", + "android.databinding", "android.drm", "android.gesture", "android.graphics", + "android.hardware", "android.inputmethodservice", "android.location", "android.media", + "android.mtp", "android.net", "android.nfc", "android.opengl", "android.os", + "android.preference", "android.print", "android.printservice", "android.provider", + "android.renderscript", "android.sax", "android.security", "android.service", + "android.speech", "android.support", "android.system", "android.telecom", + "android.telephony", "android.test", "android.text", "android.transition", + "android.util", "android.view", "android.webkit", "android.widget", "com.android.", + "dalvik.", "java.", "javax.", "org.apache.", "org.json.", "org.w3c.dom.", "org.xml.", + "org.xmlpull."}; + + private static final Pattern JAVA_FILE = Pattern.compile(".java:[0-9]+$"); + + /** + * Elides any emails in the specified {@link String} with {@link + * #EMAIL_ELISION}. + * + * @param original String potentially containing emails. + * @return String with elided emails. + */ + private static String elideEmail(String original) { + return Patterns.EMAIL_ADDRESS.matcher(original).replaceAll(EMAIL_ELISION); + } + /** + * Elides any URLs in the specified {@link String} with + * {@link #URL_ELISION}. + * + * @param original String potentially containing URLs. + * @return String with elided URLs. + */ + private static String elideUrl(String original) { + StringBuilder buffer = new StringBuilder(original); + Matcher matcher = WEB_URL.matcher(buffer); + int start = 0; + while (matcher.find(start)) { + start = matcher.start(); + int end = matcher.end(); + String url = buffer.substring(start, end); + if (!likelyToBeChromeNamespace(url) && !likelyToBeSystemNamespace(url) + && !likelyToBeCastNamespace(url) && !likelyToBeJavaFile(url)) { + buffer.replace(start, end, URL_ELISION); + end = start + URL_ELISION.length(); + matcher = WEB_URL.matcher(buffer); + } + start = end; + } + return buffer.toString(); + } + + private static boolean likelyToBeChromeNamespace(String url) { + for (String ns : CHROME_NAMESPACE) { + if (url.startsWith(ns)) { + return true; + } + } + return false; + } + + private static boolean likelyToBeSystemNamespace(String url) { + for (String ns : SYSTEM_NAMESPACE) { + if (url.startsWith(ns)) { + return true; + } + } + return false; + } + + private static boolean likelyToBeCastNamespace(String url) { + for (String ns : CAST_NAMESPACE) { + if (url.startsWith(ns)) { + return true; + } + } + return false; + } + + public static boolean likelyToBeJavaFile(String url) { + return JAVA_FILE.matcher(url).find(); + } + /** + * Elides any IP addresses in the specified {@link String} with {@link + * #IP_ELISION}. + * + * @param original String potentially containing IPs. + * @return String with elided IPs. + */ + private static String elideIp(String original) { + return Patterns.IP_ADDRESS.matcher(original).replaceAll(IP_ELISION); + } + /** + * Elides any MAC addresses in the specified {@link String} with {@link + * #MAC_ELISION}. + * + * @param original String potentially containing MACs. + * @return String with elided MACs. + */ + private static String elideMac(String original) { + return MAC_ADDRESS.matcher(original).replaceAll(MAC_ELISION); + } + /** + * Elides any console messages in the specified {@link String} with {@link + * #CONSOLE_ELISION}. + * + * @param original String potentially containing console messages. + * @return String with elided console messages. + */ + private static String elideConsole(String original) { + return CONSOLE_MSG.matcher(original).replaceAll(CONSOLE_ELISION); + } + + public static String elide(String ln) { + ln = elideEmail(ln); + ln = elideIp(ln); + ln = elideUrl(ln); + ln = elideMac(ln); + ln = elideConsole(ln); + return ln; + } +}
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatExtractor.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatExtractor.java index 2429a9a..5bf138b 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatExtractor.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/LogcatExtractor.java
@@ -1,126 +1,57 @@ // Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chromecast.shell; -import android.util.Patterns; +package org.chromium.chromecast.shell; import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; +import org.chromium.chromecast.base.CircularBuffer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; /** * Extracts logcat out of Android devices and elide PII sensitive info from it. * * <p>Elided information includes: Emails, IP address, MAC address, URL/domains as well as * Javascript console messages. - * - * <p>Caller provides a list of minidump files as well as an intent. This Callable will then extract - * the most recent logcat and save a copy for each minidump. - * - * <p>Upon completion, each minidump + logcat pairs will be passed to the MinidumpPreparationService - * along with the intent provided here. */ class LogcatExtractor { private static final String TAG = "LogcatExtractor"; private static final long HALF_SECOND = 500; - protected static final String EMAIL_ELISION = "XXX@EMAIL.ELIDED"; - @VisibleForTesting - protected static final String URL_ELISION = "HTTP://WEBADDRESS.ELIDED"; - - private static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; - - private static final Pattern IP_ADDRESS = Pattern.compile( - "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" - + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" - + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" - + "|[1-9][0-9]|[0-9]))"); - - private static final String IRI = - "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}"; - - private static final String GOOD_GTLD_CHAR = "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; - private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}"; - private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD; - - private static final Pattern DOMAIN_NAME = - Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")"); - - private static final Pattern WEB_URL = - Pattern.compile("(?:\\b|^)((?:(http|https|Http|Https|rtsp|Rtsp):" - + "\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" - + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" - + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" - + "(?:" + DOMAIN_NAME + ")" - + "(?:\\:\\d{1,5})?)" - + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" - + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" - + "(?:\\b|$)"); - - @VisibleForTesting - protected static final String IP_ELISION = "1.2.3.4"; - @VisibleForTesting - protected static final String MAC_ELISION = "01:23:45:67:89:AB"; - - @VisibleForTesting - protected static final String CONSOLE_ELISION = "[ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE"; - - private static final Pattern MAC_ADDRESS = - Pattern.compile("([0-9a-fA-F]{2}[-:]+){5}[0-9a-fA-F]{2}"); - private static final Pattern CONSOLE_MSG = Pattern.compile("\\[\\w*:CONSOLE.*\\].*"); - - private static final String[] CHROME_NAMESPACE = new String[] {"org.chromium.", "com.google."}; - - private static final String[] CAST_NAMESPACE = new String[] {"Cast.", "CastV2."}; - - private static final String[] SYSTEM_NAMESPACE = new String[] {"android.accessibilityservice", - "android.accounts", "android.animation", "android.annotation", "android.app", - "android.appwidget", "android.bluetooth", "android.content", "android.database", - "android.databinding", "android.drm", "android.gesture", "android.graphics", - "android.hardware", "android.inputmethodservice", "android.location", "android.media", - "android.mtp", "android.net", "android.nfc", "android.opengl", "android.os", - "android.preference", "android.print", "android.printservice", "android.provider", - "android.renderscript", "android.sax", "android.security", "android.service", - "android.speech", "android.support", "android.system", "android.telecom", - "android.telephony", "android.test", "android.text", "android.transition", - "android.util", "android.view", "android.webkit", "android.widget", "com.android.", - "dalvik.", "java.", "javax.", "org.apache.", "org.json.", "org.w3c.dom.", "org.xml.", - "org.xmlpull."}; - - private static final Pattern JAVA_FILE = Pattern.compile(".java:[0-9]+$"); public static String getElidedLogcat() throws IOException, InterruptedException { - List<String> rawLogcat = getLogcat(); - List<String> elidedLogcat = Collections.unmodifiableList(processLogcat(rawLogcat)); - return joinLines(elidedLogcat); + return getElidedLogcat(getLogcat()); } - private static List<String> getLogcat() throws IOException, InterruptedException { - LinkedList<String> rawLogcat = new LinkedList<String>(); + @VisibleForTesting + static String getElidedLogcat(Iterable<String> rawLogcat) { + StringBuilder builder = new StringBuilder(); + for (String line : rawLogcat) { + builder.append(LogcatElision.elide(line)); + builder.append("\n"); + } + return builder.toString(); + } + + private static Iterable<String> getLogcat() throws IOException, InterruptedException { + CircularBuffer<String> rawLogcat = new CircularBuffer<>(BuildConfig.LOGCAT_SIZE); String logLn = null; Integer exitValue = null; Process p = Runtime.getRuntime().exec("logcat -d"); BufferedReader bReader = null; try { - bReader = new BufferedReader(new InputStreamReader(p.getInputStream())); + bReader = new BufferedReader( + new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8"))); while (exitValue == null) { while ((logLn = bReader.readLine()) != null) { - // Add each new string to the end of the queue. + // Add each new string to the end of the buffer. rawLogcat.add(logLn); - if (rawLogcat.size() > BuildConfig.LOGCAT_SIZE) { - // Remove the head of the queue when it gets too large. - rawLogcat.remove(); - } } try { exitValue = p.exitValue(); @@ -134,130 +65,14 @@ throw new IOException(msg); } return rawLogcat; + } catch (UnsupportedCharsetException e) { + // Should never happen; all Java implementations are required to support UTF-8. + Log.wtf(TAG, "UTF-8 not supported", e); + return rawLogcat; } finally { if (bReader != null) { bReader.close(); } } } - - private static String joinLines(List<String> elidedLogcat) { - StringBuilder sBuilder = new StringBuilder(); - for (String ln : elidedLogcat) { - sBuilder.append(ln); - sBuilder.append("\n"); - } - return sBuilder.toString(); - } - - @VisibleForTesting - protected static List<String> processLogcat(List<String> rawLogcat) { - List<String> out = new ArrayList<String>(rawLogcat.size()); - for (String ln : rawLogcat) { - ln = elideEmail(ln); - ln = elideUrl(ln); - ln = elideIp(ln); - ln = elideMac(ln); - ln = elideConsole(ln); - out.add(ln); - } - return out; - } - /** - * Elides any emails in the specified {@link String} with {@link #EMAIL_ELISION}. - * - * @param original String potentially containing emails. - * @return String with elided emails. - */ - @VisibleForTesting - protected static String elideEmail(String original) { - return Patterns.EMAIL_ADDRESS.matcher(original).replaceAll(EMAIL_ELISION); - } - /** - * Elides any URLs in the specified {@link String} with - * {@link #URL_ELISION}. - * - * @param original String potentially containing URLs. - * @return String with elided URLs. - */ - @VisibleForTesting - protected static String elideUrl(String original) { - StringBuilder buffer = new StringBuilder(original); - Matcher matcher = WEB_URL.matcher(buffer); - int start = 0; - while (matcher.find(start)) { - start = matcher.start(); - int end = matcher.end(); - String url = buffer.substring(start, end); - if (!likelyToBeChromeNamespace(url) && !likelyToBeSystemNamespace(url) - && !likelyToBeCastNamespace(url) && !likelyToBeJavaFile(url)) { - buffer.replace(start, end, URL_ELISION); - end = start + URL_ELISION.length(); - matcher = WEB_URL.matcher(buffer); - } - start = end; - } - return buffer.toString(); - } - - public static boolean likelyToBeChromeNamespace(String url) { - for (String ns : CHROME_NAMESPACE) { - if (url.startsWith(ns)) { - return true; - } - } - return false; - } - - public static boolean likelyToBeSystemNamespace(String url) { - for (String ns : SYSTEM_NAMESPACE) { - if (url.startsWith(ns)) { - return true; - } - } - return false; - } - - public static boolean likelyToBeCastNamespace(String url) { - for (String ns : CAST_NAMESPACE) { - if (url.startsWith(ns)) { - return true; - } - } - return false; - } - - public static boolean likelyToBeJavaFile(String url) { - return JAVA_FILE.matcher(url).find(); - } - /** - * Elides any IP addresses in the specified {@link String} with {@link #IP_ELISION}. - * - * @param original String potentially containing IPs. - * @return String with elided IPs. - */ - @VisibleForTesting - protected static String elideIp(String original) { - return Patterns.IP_ADDRESS.matcher(original).replaceAll(IP_ELISION); - } - /** - * Elides any MAC addresses in the specified {@link String} with {@link #MAC_ELISION}. - * - * @param original String potentially containing MACs. - * @return String with elided MACs. - */ - @VisibleForTesting - protected static String elideMac(String original) { - return MAC_ADDRESS.matcher(original).replaceAll(MAC_ELISION); - } - /** - * Elides any console messages in the specified {@link String} with {@link #CONSOLE_ELISION}. - * - * @param original String potentially containing console messages. - * @return String with elided console messages. - */ - @VisibleForTesting - protected static String elideConsole(String original) { - return CONSOLE_MSG.matcher(original).replaceAll(CONSOLE_ELISION); - } }
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatElisionUnitTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatElisionUnitTest.java new file mode 100644 index 0000000..4015b01 --- /dev/null +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatElisionUnitTest.java
@@ -0,0 +1,142 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chromecast.shell; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * junit tests for {@link LogcatExtractor}. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class LogcatElisionUnitTest { + private static final int MAX_LINES = 5; + + @Test + public void testElideEmail() { + String original = "email me at someguy@mailservice.com"; + String expected = "email me at <EMAIL-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl() { + String original = "file bugs at crbug.com"; + String expected = "file bugs at <WEBADDRESS-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl2() { + String original = "exception at org.chromium.chrome.browser.crash.LogcatElisionUnitTest"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl3() { + String original = "file bugs at crbug.com or code.google.com"; + String expected = "file bugs at <WEBADDRESS-ELIDED> or <WEBADDRESS-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl4() { + String original = "test shorturl.com !!!"; + String expected = "test <WEBADDRESS-ELIDED> !!!"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl5() { + String original = "test just.the.perfect.len.url !!!"; + String expected = "test <WEBADDRESS-ELIDED> !!!"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl6() { + String original = "test a.very.very.very.very.very.long.url !!!"; + String expected = "test <WEBADDRESS-ELIDED> !!!"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideUrl7() { + String original = " at android.content.Intent \n at java.util.ArrayList"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testDontElideFileSuffixes() { + String original = "chromium_android_linker.so"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testElideIp() { + String original = "traceroute 127.0.0.1"; + String expected = "traceroute <IP-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideMac1() { + String original = "MAC: AB-AB-AB-AB-AB-AB"; + String expected = "MAC: <MAC-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideMac2() { + String original = "MAC: AB:AB:AB:AB:AB:AB"; + String expected = "MAC: <MAC-ELIDED>"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testElideConsole() { + String original = "I/chromium(123): [INFO:CONSOLE(2)] hello!"; + String expected = "I/chromium(123): [ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE"; + assertEquals(expected, LogcatElision.elide(original)); + } + + @Test + public void testLogTagNotElided() { + String original = "I/cr_FooBar(123): Some message"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testLogCastNotElided() { + String original = "09-08 11:52:12.569 4406 4406 I chromium: " + + "Cast.Discovery.Mdns.Request.AppId.In=25"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testLogAndroidNotElided() { + String original = "09-08 11:54:38.053 4406 4406 D cr_AvSettingsAndroid:" + + "[AvSettingsAndroid.java:180] HDMI plug update: " + + "action=android.media.action.HDMI_AUDIO_PLUG, plug=1"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testLogJavaNotElided() { + String original = "09-08 11:54:38.053 4406 4406 D cr_AvSettingsAndroid: " + + " [AvSettingsAndroid.java:187] Max channel count = 8"; + assertEquals(original, LogcatElision.elide(original)); + } + + @Test + public void testLogCcNotElided() { + String original = "09-08 11:59:12.335 4406 4443 I chromium: " + + "[4406:4443:INFO:wifi_util.cc(113)] No peers:"; + assertEquals(original, LogcatElision.elide(original)); + } +}
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatExtractorUnitTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatExtractorUnitTest.java index a46fb03..d1de556 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatExtractorUnitTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/LogcatExtractorUnitTest.java
@@ -4,145 +4,57 @@ package org.chromium.chromecast.shell; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.junit.runners.BlockJUnit4ClassRunner; -import org.chromium.testing.local.LocalRobolectricTestRunner; - +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +// TODO(sandv): Add test cases as need arises. /** - * junit tests for {@link LogcatExtractor}. + * Tests for LogcatExtractor. + * + * Full testing of elision of PII is done in LogcatElisionUnitTest. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) +@RunWith(BlockJUnit4ClassRunner.class) public class LogcatExtractorUnitTest { - private static final int MAX_LINES = 5; - @Test - public void testElideEmail() { - String original = "email me at someguy@mailservice.com"; - String expected = "email me at XXX@EMAIL.ELIDED"; - assertEquals(expected, LogcatExtractor.elideEmail(original)); + public void testEmptyLogcat() { + List<String> lines = new ArrayList<String>(); + assertEquals("", LogcatExtractor.getElidedLogcat(lines)); } @Test - public void testElideUrl() { - String original = "file bugs at crbug.com"; - String expected = "file bugs at HTTP://WEBADDRESS.ELIDED"; - assertEquals(expected, LogcatExtractor.elideUrl(original)); + public void testLogcatOfEmptyString() { + List<String> lines = Arrays.asList(""); + assertEquals("\n", LogcatExtractor.getElidedLogcat(lines)); } @Test - public void testElideUrl2() { - String original = "exception at org.chromium.chrome.browser.crash.LogcatExtractorUnitTest"; - assertEquals(original, LogcatExtractor.elideUrl(original)); + public void testJoinsLines() { + List<String> lines = Arrays.asList("a", "b", "c"); + assertEquals("a\nb\nc\n", LogcatExtractor.getElidedLogcat(lines)); } @Test - public void testElideUrl3() { - String original = "file bugs at crbug.com or code.google.com"; - String expected = "file bugs at HTTP://WEBADDRESS.ELIDED or HTTP://WEBADDRESS.ELIDED"; - assertEquals(expected, LogcatExtractor.elideUrl(original)); + public void testElidesPii() { + List<String> lines = Arrays.asList("email me at someguy@mailservice.com", + "file bugs at crbug.com", "at android.content.Intent", "at java.util.ArrayList", + "mac address: AB-AB-AB-AB-AB-AB"); + String elided = LogcatExtractor.getElidedLogcat(lines); + // PII like email addresses, web addresses, and MAC addresses are elided. + assertThat(elided, not(containsString("someguy@mailservice.com"))); + assertThat(elided, not(containsString("crbug.com"))); + assertThat(elided, not(containsString("AB-AB-AB-AB-AB-AB"))); + // Tags for class names relevant for debugging should not be elided. + assertThat(elided, containsString("android.content.Intent")); + assertThat(elided, containsString("java.util.ArrayList")); } - - @Test - public void testElideUrl4() { - String original = "test shorturl.com !!!"; - String expected = "test HTTP://WEBADDRESS.ELIDED !!!"; - assertEquals(expected, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testElideUrl5() { - String original = "test just.the.perfect.len.url !!!"; - String expected = "test HTTP://WEBADDRESS.ELIDED !!!"; - assertEquals(expected, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testElideUrl6() { - String original = "test a.very.very.very.very.very.long.url !!!"; - String expected = "test HTTP://WEBADDRESS.ELIDED !!!"; - assertEquals(expected, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testElideUrl7() { - String original = " at android.content.Intent \n at java.util.ArrayList"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testDontElideFileSuffixes() { - String original = "chromium_android_linker.so"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testElideIp() { - String original = "traceroute 127.0.0.1"; - String expected = "traceroute 1.2.3.4"; - assertEquals(expected, LogcatExtractor.elideIp(original)); - } - - @Test - public void testElideMac1() { - String original = "MAC: AB-AB-AB-AB-AB-AB"; - String expected = "MAC: 01:23:45:67:89:AB"; - assertEquals(expected, LogcatExtractor.elideMac(original)); - } - - @Test - public void testElideMac2() { - String original = "MAC: AB:AB:AB:AB:AB:AB"; - String expected = "MAC: 01:23:45:67:89:AB"; - assertEquals(expected, LogcatExtractor.elideMac(original)); - } - - @Test - public void testElideConsole() { - String original = "I/chromium(123): [INFO:CONSOLE(2)] hello!"; - String expected = "I/chromium(123): [ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE"; - assertEquals(expected, LogcatExtractor.elideConsole(original)); - } - - @Test - public void testLogTagNotElided() { - List<String> original = Arrays.asList(new String[] {"I/cr_FooBar(123): Some message"}); - assertEquals(original, LogcatExtractor.processLogcat(original)); - } - - @Test - public void testLogCastNotElided() { - String original = "09-08 11:52:12.569 4406 4406 I chromium: " - + "Cast.Discovery.Mdns.Request.AppId.In=25"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testLogAndroidNotElided() { - String original = "09-08 11:54:38.053 4406 4406 D cr_AvSettingsAndroid:" - + "[AvSettingsAndroid.java:180] HDMI plug update: " - + "action=android.media.action.HDMI_AUDIO_PLUG, plug=1"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testLogJavaNotElided() { - String original = "09-08 11:54:38.053 4406 4406 D cr_AvSettingsAndroid: " - + " [AvSettingsAndroid.java:187] Max channel count = 8"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } - - @Test - public void testLogCcNotElided() { - String original = "09-08 11:59:12.335 4406 4443 I chromium: " - + "[4406:4443:INFO:wifi_util.cc(113)] No peers:"; - assertEquals(original, LogcatExtractor.elideUrl(original)); - } -} \ No newline at end of file +}
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc index d2a6d80..ef430518 100644 --- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc +++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -889,13 +889,11 @@ } void AudioVideoPipelineDeviceTest::EndImmediateEosTest() { - EXPECT_EQ(kStartPts, backend_->GetCurrentPts()); RunPlaybackChecks(); ASSERT_TRUE(backend_->Pause()); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kStartPts, backend_->GetCurrentPts()); RunPlaybackChecks(); backend_->Stop();
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc index 44b40c7..e3e7b5f6 100644 --- a/chromeos/dbus/cros_disks_client.cc +++ b/chromeos/dbus/cros_disks_client.cc
@@ -15,6 +15,7 @@ #include "base/files/file_util.h" #include "base/location.h" #include "base/macros.h" +#include "base/observer_list.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" @@ -94,7 +95,17 @@ // The CrosDisksClient implementation. class CrosDisksClientImpl : public CrosDisksClient { public: - CrosDisksClientImpl() : proxy_(NULL), weak_ptr_factory_(this) {} + CrosDisksClientImpl() : proxy_(nullptr), weak_ptr_factory_(this) {} + + // CrosDisksClient override. + void AddObserver(Observer* observer) override { + observer_list_.AddObserver(observer); + } + + // CrosDisksClient override. + void RemoveObserver(Observer* observer) override { + observer_list_.RemoveObserver(observer); + } // CrosDisksClient override. void Mount(const std::string& source_path, @@ -223,74 +234,50 @@ error_callback)); } - // CrosDisksClient override. - void SetMountEventHandler( - const MountEventHandler& mount_event_handler) override { - static const SignalEventTuple kSignalEventTuples[] = { - { cros_disks::kDeviceAdded, CROS_DISKS_DEVICE_ADDED }, - { cros_disks::kDeviceScanned, CROS_DISKS_DEVICE_SCANNED }, - { cros_disks::kDeviceRemoved, CROS_DISKS_DEVICE_REMOVED }, - { cros_disks::kDiskAdded, CROS_DISKS_DISK_ADDED }, - { cros_disks::kDiskChanged, CROS_DISKS_DISK_CHANGED }, - { cros_disks::kDiskRemoved, CROS_DISKS_DISK_REMOVED }, - }; - const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples); - - for (size_t i = 0; i < kNumSignalEventTuples; ++i) { - proxy_->ConnectToSignal( - cros_disks::kCrosDisksInterface, - kSignalEventTuples[i].signal_name, - base::Bind(&CrosDisksClientImpl::OnMountEvent, - weak_ptr_factory_.GetWeakPtr(), - kSignalEventTuples[i].event_type, - mount_event_handler), - base::Bind(&CrosDisksClientImpl::OnSignalConnected, - weak_ptr_factory_.GetWeakPtr())); - } - } - - // CrosDisksClient override. - void SetMountCompletedHandler( - const MountCompletedHandler& mount_completed_handler) override { - proxy_->ConnectToSignal( - cros_disks::kCrosDisksInterface, - cros_disks::kMountCompleted, - base::Bind(&CrosDisksClientImpl::OnMountCompleted, - weak_ptr_factory_.GetWeakPtr(), - mount_completed_handler), - base::Bind(&CrosDisksClientImpl::OnSignalConnected, - weak_ptr_factory_.GetWeakPtr())); - } - - // CrosDisksClient override. - void SetFormatCompletedHandler( - const FormatCompletedHandler& format_completed_handler) override { - proxy_->ConnectToSignal( - cros_disks::kCrosDisksInterface, - cros_disks::kFormatCompleted, - base::Bind(&CrosDisksClientImpl::OnFormatCompleted, - weak_ptr_factory_.GetWeakPtr(), - format_completed_handler), - base::Bind(&CrosDisksClientImpl::OnSignalConnected, - weak_ptr_factory_.GetWeakPtr())); - } - - // CrosDisksClient override. - void SetRenameCompletedHandler( - const RenameCompletedHandler& rename_completed_handler) override { - proxy_->ConnectToSignal( - cros_disks::kCrosDisksInterface, cros_disks::kRenameCompleted, - base::Bind(&CrosDisksClientImpl::OnRenameCompleted, - weak_ptr_factory_.GetWeakPtr(), rename_completed_handler), - base::Bind(&CrosDisksClientImpl::OnSignalConnected, - weak_ptr_factory_.GetWeakPtr())); - } - protected: void Init(dbus::Bus* bus) override { proxy_ = bus->GetObjectProxy( cros_disks::kCrosDisksServiceName, dbus::ObjectPath(cros_disks::kCrosDisksServicePath)); + + // Register handlers for D-Bus signals. + constexpr SignalEventTuple kSignalEventTuples[] = { + {cros_disks::kDeviceAdded, CROS_DISKS_DEVICE_ADDED}, + {cros_disks::kDeviceScanned, CROS_DISKS_DEVICE_SCANNED}, + {cros_disks::kDeviceRemoved, CROS_DISKS_DEVICE_REMOVED}, + {cros_disks::kDiskAdded, CROS_DISKS_DISK_ADDED}, + {cros_disks::kDiskChanged, CROS_DISKS_DISK_CHANGED}, + {cros_disks::kDiskRemoved, CROS_DISKS_DISK_REMOVED}, + }; + for (const auto& entry : kSignalEventTuples) { + proxy_->ConnectToSignal( + cros_disks::kCrosDisksInterface, entry.signal_name, + base::BindRepeating(&CrosDisksClientImpl::OnMountEvent, + weak_ptr_factory_.GetWeakPtr(), entry.event_type), + base::BindOnce(&CrosDisksClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + } + + proxy_->ConnectToSignal( + cros_disks::kCrosDisksInterface, cros_disks::kMountCompleted, + base::BindRepeating(&CrosDisksClientImpl::OnMountCompleted, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&CrosDisksClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + cros_disks::kCrosDisksInterface, cros_disks::kFormatCompleted, + base::BindRepeating(&CrosDisksClientImpl::OnFormatCompleted, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&CrosDisksClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + cros_disks::kCrosDisksInterface, cros_disks::kRenameCompleted, + base::BindRepeating(&CrosDisksClientImpl::OnRenameCompleted, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&CrosDisksClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); } private: @@ -429,32 +416,34 @@ callback.Run(disk); } - // Handles mount event signals and calls |handler|. - void OnMountEvent(MountEventType event_type, - MountEventHandler handler, - dbus::Signal* signal) { + // Handles mount event signals and notifies observers. + void OnMountEvent(MountEventType event_type, dbus::Signal* signal) { dbus::MessageReader reader(signal); std::string device; if (!reader.PopString(&device)) { LOG(ERROR) << "Invalid signal: " << signal->ToString(); return; } - handler.Run(event_type, device); + + for (auto& observer : observer_list_) + observer.OnMountEvent(event_type, device); } - // Handles MountCompleted signal and calls |handler|. - void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) { + // Handles MountCompleted signal and notifies observers. + void OnMountCompleted(dbus::Signal* signal) { dbus::MessageReader reader(signal); MountEntry entry; if (!ReadMountEntryFromDbus(&reader, &entry)) { LOG(ERROR) << "Invalid signal: " << signal->ToString(); return; } - handler.Run(entry); + + for (auto& observer : observer_list_) + observer.OnMountCompleted(entry); } - // Handles FormatCompleted signal and calls |handler|. - void OnFormatCompleted(FormatCompletedHandler handler, dbus::Signal* signal) { + // Handles FormatCompleted signal and notifies observers. + void OnFormatCompleted(dbus::Signal* signal) { dbus::MessageReader reader(signal); uint32_t error_code = 0; std::string device_path; @@ -462,11 +451,15 @@ LOG(ERROR) << "Invalid signal: " << signal->ToString(); return; } - handler.Run(static_cast<FormatError>(error_code), device_path); + + for (auto& observer : observer_list_) { + observer.OnFormatCompleted(static_cast<FormatError>(error_code), + device_path); + } } - // Handles RenameCompleted signal and calls |handler|. - void OnRenameCompleted(RenameCompletedHandler handler, dbus::Signal* signal) { + // Handles RenameCompleted signal and notifies observers. + void OnRenameCompleted(dbus::Signal* signal) { dbus::MessageReader reader(signal); uint32_t error_code = 0; std::string device_path; @@ -474,7 +467,11 @@ LOG(ERROR) << "Invalid signal: " << signal->ToString(); return; } - handler.Run(static_cast<RenameError>(error_code), device_path); + + for (auto& observer : observer_list_) { + observer.OnRenameCompleted(static_cast<RenameError>(error_code), + device_path); + } } // Handles the result of signal connection setup. @@ -487,6 +484,8 @@ dbus::ObjectProxy* proxy_; + base::ObserverList<Observer> observer_list_; + // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
diff --git a/chromeos/dbus/cros_disks_client.h b/chromeos/dbus/cros_disks_client.h index d571986..c6afed07 100644 --- a/chromeos/dbus/cros_disks_client.h +++ b/chromeos/dbus/cros_disks_client.h
@@ -280,32 +280,35 @@ typedef base::Callback<void(const DiskInfo& disk_info)> GetDevicePropertiesCallback; - // A callback to handle MountCompleted signal. - typedef base::Callback<void(const MountEntry& entry)> MountCompletedHandler; + class Observer { + public: + // Called when a mount event signal is received. + virtual void OnMountEvent(MountEventType event_type, + const std::string& device_path) = 0; - // A callback to handle FormatCompleted signal. - // The first argument is the error code. - // The second argument is the device path. - typedef base::Callback<void(FormatError error_code, - const std::string& device_path)> - FormatCompletedHandler; + // Called when a MountCompleted signal is received. + virtual void OnMountCompleted(const MountEntry& entry) = 0; - // A callback to handle RenameCompleted signal. - // The first argument is the error code. - // The second argument is the device path. - typedef base::Callback<void(RenameError error_code, - const std::string& device_path)> - RenameCompletedHandler; + // Called when a FormatCompleted signal is received. + virtual void OnFormatCompleted(FormatError error_code, + const std::string& device_path) = 0; - // A callback to handle mount events. - // The first argument is the event type. - // The second argument is the device path. - typedef base::Callback<void(MountEventType event_type, - const std::string& device_path)> - MountEventHandler; + // Called when a RenameCompleted signal is received. + virtual void OnRenameCompleted(RenameError error_code, + const std::string& device_path) = 0; + + protected: + virtual ~Observer() = default; + }; ~CrosDisksClient() override; + // Registers the given |observer| to listen D-Bus signals. + virtual void AddObserver(Observer* observer) = 0; + + // Unregisters the |observer| from this instance. + virtual void RemoveObserver(Observer* observer) = 0; + // Calls Mount method. |callback| is called after the method call succeeds, // otherwise, |error_callback| is called. // When mounting an archive, caller may set two optional arguments: @@ -367,26 +370,6 @@ const GetDevicePropertiesCallback& callback, const base::Closure& error_callback) = 0; - // Registers |mount_event_handler| as a callback to be invoked when a mount - // event signal is received. - virtual void SetMountEventHandler( - const MountEventHandler& mount_event_handler) = 0; - - // Registers |mount_completed_handler| as a callback to be invoked when a - // MountCompleted signal is received. - virtual void SetMountCompletedHandler( - const MountCompletedHandler& mount_completed_handler) = 0; - - // Registers |format_completed_handler| as a callback to be invoked when a - // FormatCompleted signal is received. - virtual void SetFormatCompletedHandler( - const FormatCompletedHandler& format_completed_handler) = 0; - - // Registers |rename_completed_handler| as a callback to be invoked when a - // RenameCompleted signal is received. - virtual void SetRenameCompletedHandler( - const RenameCompletedHandler& rename_completed_handler) = 0; - // Factory function, creates a new instance and returns ownership. // For normal usage, access the singleton via DBusThreadManager::Get(). static CrosDisksClient* Create(DBusClientImplementationType type);
diff --git a/chromeos/dbus/fake_cros_disks_client.cc b/chromeos/dbus/fake_cros_disks_client.cc index 9de08922..31c205d7 100644 --- a/chromeos/dbus/fake_cros_disks_client.cc +++ b/chromeos/dbus/fake_cros_disks_client.cc
@@ -4,6 +4,8 @@ #include "chromeos/dbus/fake_cros_disks_client.h" +#include <utility> + #include "base/bind.h" #include "base/files/file_util.h" #include "base/location.h" @@ -40,26 +42,6 @@ return MOUNT_ERROR_NONE; } -// Continuation of Mount(). -void DidMount(const CrosDisksClient::MountCompletedHandler& - mount_completed_handler, - const std::string& source_path, - MountType type, - const base::Closure& callback, - const base::FilePath& mounted_path, - MountError mount_error) { - // Tell the caller of Mount() that the mount request was accepted. - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback); - - // Tell the caller of Mount() that the mount completed. - if (!mount_completed_handler.is_null()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(mount_completed_handler, - MountEntry(mount_error, source_path, type, - mounted_path.AsUTF8Unsafe()))); - } -} - } // namespace FakeCrosDisksClient::FakeCrosDisksClient() @@ -68,13 +50,22 @@ format_call_count_(0), format_success_(true), rename_call_count_(0), - rename_success_(true) {} + rename_success_(true), + weak_ptr_factory_(this) {} FakeCrosDisksClient::~FakeCrosDisksClient() = default; void FakeCrosDisksClient::Init(dbus::Bus* bus) { } +void FakeCrosDisksClient::AddObserver(Observer* observer) { + observer_list_.AddObserver(observer); +} + +void FakeCrosDisksClient::RemoveObserver(Observer* observer) { + observer_list_.RemoveObserver(observer); +} + void FakeCrosDisksClient::Mount(const std::string& source_path, const std::string& source_format, const std::string& mount_label, @@ -85,7 +76,7 @@ // This fake implementation assumes mounted path is device when source_format // is empty, or an archive otherwise. MountType type = - (source_format == "") ? MOUNT_TYPE_DEVICE : MOUNT_TYPE_ARCHIVE; + source_format.empty() ? MOUNT_TYPE_DEVICE : MOUNT_TYPE_ARCHIVE; base::FilePath mounted_path; switch (type) { @@ -98,7 +89,7 @@ base::FilePath::FromUTF8Unsafe(mount_label)); break; case MOUNT_TYPE_INVALID: - // Unreachable + NOTREACHED(); return; } mounted_paths_.insert(mounted_path); @@ -106,9 +97,23 @@ base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::Bind(&PerformFakeMount, source_path, mounted_path), - base::Bind(&DidMount, mount_completed_handler_, source_path, type, - callback, mounted_path)); + base::BindOnce(&PerformFakeMount, source_path, mounted_path), + base::BindOnce(&FakeCrosDisksClient::DidMount, + weak_ptr_factory_.GetWeakPtr(), source_path, type, + callback, mounted_path)); +} + +void FakeCrosDisksClient::DidMount(const std::string& source_path, + MountType type, + base::OnceClosure callback, + const base::FilePath& mounted_path, + MountError mount_error) { + // Tell the caller of Mount() that the mount request was accepted. + std::move(callback).Run(); + + // Notify observers that the mount is completed. + NotifyMountCompleted(mount_error, source_path, type, + mounted_path.AsUTF8Unsafe()); } void FakeCrosDisksClient::Unmount(const std::string& device_path, @@ -193,62 +198,28 @@ const base::Closure& error_callback) { } -void FakeCrosDisksClient::SetMountEventHandler( - const MountEventHandler& mount_event_handler) { - mount_event_handler_ = mount_event_handler; +void FakeCrosDisksClient::NotifyMountCompleted(MountError error_code, + const std::string& source_path, + MountType mount_type, + const std::string& mount_path) { + for (auto& observer : observer_list_) { + observer.OnMountCompleted( + MountEntry(error_code, source_path, mount_type, mount_path)); + } } -void FakeCrosDisksClient::SetMountCompletedHandler( - const MountCompletedHandler& mount_completed_handler) { - mount_completed_handler_ = mount_completed_handler; -} - -void FakeCrosDisksClient::SetFormatCompletedHandler( - const FormatCompletedHandler& format_completed_handler) { - format_completed_handler_ = format_completed_handler; -} - -void FakeCrosDisksClient::SetRenameCompletedHandler( - const RenameCompletedHandler& rename_completed_handler) { - rename_completed_handler_ = rename_completed_handler; -} - -bool FakeCrosDisksClient::SendMountEvent(MountEventType event, - const std::string& path) { - if (mount_event_handler_.is_null()) - return false; - mount_event_handler_.Run(event, path); - return true; -} - -bool FakeCrosDisksClient::SendMountCompletedEvent( - MountError error_code, - const std::string& source_path, - MountType mount_type, - const std::string& mount_path) { - if (mount_completed_handler_.is_null()) - return false; - mount_completed_handler_.Run( - MountEntry(error_code, source_path, mount_type, mount_path)); - return true; -} - -bool FakeCrosDisksClient::SendFormatCompletedEvent( +void FakeCrosDisksClient::NotifyFormatCompleted( FormatError error_code, const std::string& device_path) { - if (format_completed_handler_.is_null()) - return false; - format_completed_handler_.Run(error_code, device_path); - return true; + for (auto& observer : observer_list_) + observer.OnFormatCompleted(error_code, device_path); } -bool FakeCrosDisksClient::SendRenameCompletedEvent( +void FakeCrosDisksClient::NotifyRenameCompleted( RenameError error_code, const std::string& device_path) { - if (rename_completed_handler_.is_null()) - return false; - rename_completed_handler_.Run(error_code, device_path); - return true; + for (auto& observer : observer_list_) + observer.OnRenameCompleted(error_code, device_path); } } // namespace chromeos
diff --git a/chromeos/dbus/fake_cros_disks_client.h b/chromeos/dbus/fake_cros_disks_client.h index 495d97f..c9d2a88 100644 --- a/chromeos/dbus/fake_cros_disks_client.h +++ b/chromeos/dbus/fake_cros_disks_client.h
@@ -10,6 +10,9 @@ #include "base/callback.h" #include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "chromeos/dbus/cros_disks_client.h" namespace chromeos { @@ -23,6 +26,8 @@ // CrosDisksClient overrides void Init(dbus::Bus* bus) override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; // Performs fake mounting for archive files. Instead of actually extracting // contents of archive files, this function creates a directory that @@ -58,27 +63,17 @@ void GetDeviceProperties(const std::string& device_path, const GetDevicePropertiesCallback& callback, const base::Closure& error_callback) override; - void SetMountEventHandler( - const MountEventHandler& mount_event_handler) override; - void SetMountCompletedHandler( - const MountCompletedHandler& mount_completed_handler) override; - void SetFormatCompletedHandler( - const FormatCompletedHandler& format_completed_handler) override; - void SetRenameCompletedHandler( - const RenameCompletedHandler& rename_completed_handler) override; // Used in tests to simulate signals sent by cros disks layer. - // Invokes handlers set in |SetMountEventHandler|, |SetMountCompletedHandler|, - // and |SetFormatCompletedHandler|. - bool SendMountEvent(MountEventType event, const std::string& path); - bool SendMountCompletedEvent(MountError error_code, - const std::string& source_path, - MountType mount_type, - const std::string& mount_path); - bool SendFormatCompletedEvent(FormatError error_code, - const std::string& device_path); - bool SendRenameCompletedEvent(RenameError error_code, - const std::string& device_path); + // Calls corresponding methods of the registered observers. + void NotifyMountCompleted(MountError error_code, + const std::string& source_path, + MountType mount_type, + const std::string& mount_path); + void NotifyFormatCompleted(FormatError error_code, + const std::string& device_path); + void NotifyRenameCompleted(RenameError error_code, + const std::string& device_path); // Returns how many times Unmount() was called. int unmount_call_count() const { @@ -143,11 +138,14 @@ void MakeRenameFail() { rename_success_ = false; } private: - MountEventHandler mount_event_handler_; - MountCompletedHandler mount_completed_handler_; - FormatCompletedHandler format_completed_handler_; - RenameCompletedHandler rename_completed_handler_; + // Continuation of Mount(). + void DidMount(const std::string& source_path, + MountType type, + base::OnceClosure callback, + const base::FilePath& mounted_path, + MountError mount_error); + base::ObserverList<Observer> observer_list_; int unmount_call_count_; std::string last_unmount_device_path_; UnmountOptions last_unmount_options_; @@ -162,6 +160,10 @@ std::string last_rename_volume_name_; bool rename_success_; std::set<base::FilePath> mounted_paths_; + + base::WeakPtrFactory<FakeCrosDisksClient> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(FakeCrosDisksClient); }; } // namespace chromeos
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc index cc18683..ad80c3be 100644 --- a/chromeos/disks/disk_mount_manager.cc +++ b/chromeos/disks/disk_mount_manager.cc
@@ -10,6 +10,8 @@ #include <map> #include <set> #include <string> +#include <utility> +#include <vector> #include "base/bind.h" #include "base/macros.h" @@ -17,6 +19,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/strings/string_util.h" +#include "chromeos/dbus/cros_disks_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/disks/suspend_unmount_manager.h" @@ -32,7 +35,8 @@ DiskMountManager* g_disk_mount_manager = NULL; // The DiskMountManager implementation. -class DiskMountManagerImpl : public DiskMountManager { +class DiskMountManagerImpl : public DiskMountManager, + public CrosDisksClient::Observer { public: DiskMountManagerImpl() : already_refreshed_(false), @@ -43,29 +47,18 @@ dbus_thread_manager->GetPowerManagerClient(); suspend_unmount_manager_.reset( new SuspendUnmountManager(this, power_manager_client)); - cros_disks_client_->SetMountEventHandler( - base::Bind(&DiskMountManagerImpl::OnMountEvent, - weak_ptr_factory_.GetWeakPtr())); - cros_disks_client_->SetMountCompletedHandler( - base::Bind(&DiskMountManagerImpl::OnMountCompleted, - weak_ptr_factory_.GetWeakPtr())); - cros_disks_client_->SetFormatCompletedHandler( - base::Bind(&DiskMountManagerImpl::OnFormatCompleted, - weak_ptr_factory_.GetWeakPtr())); - cros_disks_client_->SetRenameCompletedHandler( - base::Bind(&DiskMountManagerImpl::OnRenameCompleted, - weak_ptr_factory_.GetWeakPtr())); + cros_disks_client_->AddObserver(this); } - ~DiskMountManagerImpl() override = default; + ~DiskMountManagerImpl() override { cros_disks_client_->RemoveObserver(this); } // DiskMountManager override. - void AddObserver(Observer* observer) override { + void AddObserver(DiskMountManager::Observer* observer) override { observers_.AddObserver(observer); } // DiskMountManager override. - void RemoveObserver(Observer* observer) override { + void RemoveObserver(DiskMountManager::Observer* observer) override { observers_.RemoveObserver(observer); } @@ -425,8 +418,8 @@ } } - // Callback to handle MountCompleted signal and Mount method call failure. - void OnMountCompleted(const MountEntry& entry) { + // CrosDisksClient::Observer override. + void OnMountCompleted(const MountEntry& entry) override { MountCondition mount_condition = MOUNT_CONDITION_NONE; if (entry.mount_type() == MOUNT_TYPE_DEVICE) { if (entry.error_code() == MOUNT_ERROR_UNKNOWN_FILESYSTEM) { @@ -547,9 +540,9 @@ NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path); } - // Callback to handle FormatCompleted signal and Format method call failure. + // CrosDisksClient::Observer override. void OnFormatCompleted(FormatError error_code, - const std::string& device_path) { + const std::string& device_path) override { auto iter = disks_.find(device_path); // disk might have been removed by now? @@ -603,9 +596,9 @@ NotifyRenameStatusUpdate(RENAME_STARTED, RENAME_ERROR_NONE, device_path); } - // Callback to handle RenameCompleted signal and Rename method call failure. + // CrosDisksClient::Observer override. void OnRenameCompleted(RenameError error_code, - const std::string& device_path) { + const std::string& device_path) override { auto iter = disks_.find(device_path); // disk might have been removed by now? @@ -724,8 +717,9 @@ refresh_callbacks_.clear(); } - // Callback to handle mount event signals. - void OnMountEvent(MountEventType event, const std::string& device_path_arg) { + // CrosDisksClient::Observer override. + void OnMountEvent(MountEventType event, + const std::string& device_path_arg) override { // Take a copy of the argument so we can modify it below. std::string device_path = device_path_arg; switch (event) { @@ -819,7 +813,7 @@ } // Mount event change observers. - base::ObserverList<Observer> observers_; + base::ObserverList<DiskMountManager::Observer> observers_; CrosDisksClient* cros_disks_client_; @@ -913,7 +907,7 @@ // Only the second condition is checked here, because Disks are created from // non-virtual mount devices only. return !on_boot_device_; -}; +} bool DiskMountManager::Disk::IsStatefulPartition() const { return mount_path_ == kStatefulPartition;
diff --git a/chromeos/disks/disk_mount_manager_unittest.cc b/chromeos/disks/disk_mount_manager_unittest.cc index 7d4fad3..da0da33 100644 --- a/chromeos/disks/disk_mount_manager_unittest.cc +++ b/chromeos/disks/disk_mount_manager_unittest.cc
@@ -6,6 +6,9 @@ #include <stdint.h> #include <memory> +#include <string> +#include <utility> +#include <vector> #include "base/bind.h" #include "base/run_loop.h" @@ -793,8 +796,8 @@ // Send failing FORMAT_COMPLETED signal. // The failure is marked by ! in fromt of the path (but this should change // soon). - fake_cros_disks_client_->SendFormatCompletedEvent( - chromeos::FORMAT_ERROR_UNKNOWN, kDevice1SourcePath); + fake_cros_disks_client_->NotifyFormatCompleted(chromeos::FORMAT_ERROR_UNKNOWN, + kDevice1SourcePath); // The observer should get notified that the device was unmounted and that // formatting has started. @@ -840,8 +843,8 @@ EXPECT_FALSE(HasMountPoint(kDevice1MountPath)); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendFormatCompletedEvent(chromeos::FORMAT_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyFormatCompleted(chromeos::FORMAT_ERROR_NONE, + kDevice1SourcePath); // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED // events (all of them without an error set). @@ -886,11 +889,11 @@ EXPECT_FALSE(HasMountPoint(kDevice1MountPath)); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendFormatCompletedEvent(chromeos::FORMAT_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyFormatCompleted(chromeos::FORMAT_ERROR_NONE, + kDevice1SourcePath); // Simulate the device remounting. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kDevice1SourcePath, chromeos::MOUNT_TYPE_DEVICE, kDevice1MountPath); @@ -913,8 +916,8 @@ EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem()); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendFormatCompletedEvent(chromeos::FORMAT_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyFormatCompleted(chromeos::FORMAT_ERROR_NONE, + kDevice1SourcePath); // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED // events (all of them without an error set) twice (once for each formatting @@ -957,10 +960,10 @@ chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_ACCESS_MODE_READ_ONLY); // Simulate cros_disks reporting mount completed. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kSourcePath1, chromeos::MOUNT_TYPE_DEVICE, kMountPath1); - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kSourcePath2, chromeos::MOUNT_TYPE_DEVICE, kMountPath2); @@ -999,7 +1002,7 @@ chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_ACCESS_MODE_READ_WRITE); // Simulate cros_disks reporting mount completed. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kReadOnlyDeviceSourcePath, chromeos::MOUNT_TYPE_DEVICE, kReadOnlyDeviceMountPath); @@ -1022,7 +1025,7 @@ manager->RemountAllRemovableDrives(chromeos::MOUNT_ACCESS_MODE_READ_ONLY); // Simulate cros_disks reporting mount completed. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kDevice1SourcePath, chromeos::MOUNT_TYPE_DEVICE, kDevice1MountPath); @@ -1040,7 +1043,7 @@ manager->RemountAllRemovableDrives(chromeos::MOUNT_ACCESS_MODE_READ_WRITE); // Simulate cros_disks reporting mount completed. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kDevice1SourcePath, chromeos::MOUNT_TYPE_DEVICE, kDevice1MountPath); // Event handlers of observers should be called. @@ -1246,8 +1249,8 @@ // Send failing RENAME_COMPLETED signal. // The failure is marked by ! in fromt of the path (but this should change // soon). - fake_cros_disks_client_->SendRenameCompletedEvent( - chromeos::RENAME_ERROR_UNKNOWN, kDevice1SourcePath); + fake_cros_disks_client_->NotifyRenameCompleted(chromeos::RENAME_ERROR_UNKNOWN, + kDevice1SourcePath); // The observer should get notified that the device was unmounted and that // renaming has started. @@ -1293,8 +1296,8 @@ EXPECT_FALSE(HasMountPoint(kDevice1MountPath)); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendRenameCompletedEvent(chromeos::RENAME_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyRenameCompleted(chromeos::RENAME_ERROR_NONE, + kDevice1SourcePath); // The observer should receive UNMOUNTING, RENAME_STARTED and RENAME_COMPLETED // events (all of them without an error set). @@ -1342,11 +1345,11 @@ EXPECT_FALSE(HasMountPoint(kDevice1MountPath)); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendRenameCompletedEvent(chromeos::RENAME_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyRenameCompleted(chromeos::RENAME_ERROR_NONE, + kDevice1SourcePath); // Simulate the device remounting. - fake_cros_disks_client_->SendMountCompletedEvent( + fake_cros_disks_client_->NotifyMountCompleted( chromeos::MOUNT_ERROR_NONE, kDevice1SourcePath, chromeos::MOUNT_TYPE_DEVICE, kDevice1MountPath); @@ -1374,8 +1377,8 @@ disks.find(kDevice1SourcePath)->second->base_mount_path()); // Simulate cros_disks reporting success. - fake_cros_disks_client_->SendRenameCompletedEvent(chromeos::RENAME_ERROR_NONE, - kDevice1SourcePath); + fake_cros_disks_client_->NotifyRenameCompleted(chromeos::RENAME_ERROR_NONE, + kDevice1SourcePath); // The observer should receive UNMOUNTING, RENAME_STARTED and RENAME_COMPLETED // events (all of them without an error set) twice (once for each renaming
diff --git a/components/autofill/android/autofill_provider_android.cc b/components/autofill/android/autofill_provider_android.cc index 88c8ae11..ca83aaa 100644 --- a/components/autofill/android/autofill_provider_android.cc +++ b/components/autofill/android/autofill_provider_android.cc
@@ -122,6 +122,29 @@ transformed_bounding.width(), transformed_bounding.height()); } +void AutofillProviderAndroid::OnTextFieldDidScroll( + AutofillHandlerProxy* handler, + const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + size_t index; + if (!IsCurrentlyLinkedHandler(handler) || !IsCurrentlyLinkedForm(form) || + !form_->GetSimilarFieldIndex(field, &index)) + return; + + form_->OnTextFieldDidChange(index, field.value); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) + return; + + gfx::RectF transformed_bounding = ToClientAreaBound(bounding_box); + Java_AutofillProvider_onTextFieldDidScroll( + env, obj, index, transformed_bounding.x(), transformed_bounding.y(), + transformed_bounding.width(), transformed_bounding.height()); +} + bool AutofillProviderAndroid::OnWillSubmitForm( AutofillHandlerProxy* handler, const FormData& form,
diff --git a/components/autofill/android/autofill_provider_android.h b/components/autofill/android/autofill_provider_android.h index 9ab0a897..463aa1b 100644 --- a/components/autofill/android/autofill_provider_android.h +++ b/components/autofill/android/autofill_provider_android.h
@@ -36,6 +36,10 @@ const FormFieldData& field, const gfx::RectF& bounding_box, const base::TimeTicks timestamp) override; + void OnTextFieldDidScroll(AutofillHandlerProxy* handler, + const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override; bool OnWillSubmitForm(AutofillHandlerProxy* handler, const FormData& form, const base::TimeTicks timestamp) override;
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java index e79d4b0..b2d96b4 100644 --- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java +++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -76,7 +76,7 @@ FormData formData, int focus, float x, float y, float width, float height); /** - * Invoked when text field is changed. + * Invoked when text field's value is changed. * * @param index index of field in current form. * @param x the boundary of focus field. @@ -90,6 +90,20 @@ int index, float x, float y, float width, float height); /** + * Invoked when text field is scrolled. + * + * @param index index of field in current form. + * @param x the boundary of focus field. + * @param y the boundary of focus field. + * @param width the boundary of focus field. + * @param height the boundary of focus field. + * + */ + @CalledByNative + protected abstract void onTextFieldDidScroll( + int index, float x, float y, float width, float height); + + /** * Invoked when current form will be submitted. * */
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index 0cf792b..e7ce3745 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -45,6 +45,7 @@ autofill_handler_ = base::MakeUnique<AutofillHandlerProxy>(this, provider); GetAutofillAgent()->SetUserGestureRequired(false); GetAutofillAgent()->SetSecureContextRequired(true); + GetAutofillAgent()->SetFocusRequiresScroll(false); } else { autofill_handler_ = base::MakeUnique<AutofillManager>( this, client, app_locale, enable_download_manager); @@ -206,6 +207,12 @@ autofill_handler_->OnTextFieldDidChange(form, field, bounding_box, timestamp); } +void ContentAutofillDriver::TextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) { + autofill_handler_->OnTextFieldDidScroll(form, field, bounding_box); +} + void ContentAutofillDriver::QueryFormFieldAutofill( int32_t id, const FormData& form,
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index 61684b5..624f87bb1 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -80,6 +80,9 @@ const FormFieldData& field, const gfx::RectF& bounding_box, base::TimeTicks timestamp) override; + void TextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override; void QueryFormFieldAutofill(int32_t id, const FormData& form, const FormFieldData& field,
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc index 2bb5a3b..52af5253 100644 --- a/components/autofill/content/browser/content_autofill_driver_unittest.cc +++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -206,6 +206,8 @@ void SetSecureContextRequired(bool required) override {} + void SetFocusRequiresScroll(bool require) override {} + mojo::BindingSet<mojom::AutofillAgent> bindings_; base::Closure quit_closure_;
diff --git a/components/autofill/content/common/autofill_agent.mojom b/components/autofill/content/common/autofill_agent.mojom index df5e5a2..8e41cdc 100644 --- a/components/autofill/content/common/autofill_agent.mojom +++ b/components/autofill/content/common/autofill_agent.mojom
@@ -64,6 +64,9 @@ // Configures the render to require, or not, the secure context to query // autofill suggestion, the default is false. SetSecureContextRequired(bool required); + + // Configures whether scroll is required in order to complete focus. The default is true. + SetFocusRequiresScroll(bool require); }; // There is one instance of this interface per render frame in the render
diff --git a/components/autofill/content/common/autofill_driver.mojom b/components/autofill/content/common/autofill_driver.mojom index f04cf1af13a..e3a18f08 100644 --- a/components/autofill/content/common/autofill_driver.mojom +++ b/components/autofill/content/common/autofill_driver.mojom
@@ -30,6 +30,11 @@ gfx.mojom.RectF bounding_box, mojo.common.mojom.TimeTicks timestamp); + // Notification that a form field has scrolled. + TextFieldDidScroll(FormData form, + FormFieldData field, + gfx.mojom.RectF bounding_box); + // Queries the browser for Autofill suggestions for a form input field. // |id| is the request ID which is used to map responses correctly. QueryFormFieldAutofill(int32 id, @@ -77,13 +82,13 @@ // Notification that this password form was submitted by the user. PasswordFormSubmitted(PasswordForm password_form); - + // Notification that a user starts typing in password fields and the omnibox // icon with anchored save/update prompt should be available. ShowManualFallbackForSaving(PasswordForm password_form); - - // Notification that there is no user input in password fields and the - // save/update prompt anchored to the omnibox icon should be removed. + + // Notification that there is no user input in password fields and the + // save/update prompt anchored to the omnibox icon should be removed. HideManualFallbackForSaving(); // Notification that in-page navigation happened and at this moment we have
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 5168ecf..8712c83f 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -211,6 +211,18 @@ } void AutofillAgent::DidChangeScrollOffset() { + if (!focus_requires_scroll_ && is_popup_possibly_visible_ && + element_.Focused()) { + FormData form; + FormFieldData field; + if (form_util::FindFormAndFieldForFormControlElement(element_, &form, + &field)) { + GetAutofillDriver()->TextFieldDidScroll( + form, field, + render_frame()->GetRenderView()->ElementBoundsInWindow(element_)); + } + } + if (IsKeyboardAccessoryEnabled()) return; @@ -220,7 +232,7 @@ void AutofillAgent::FocusedNodeChanged(const WebNode& node) { was_focused_before_now_ = false; - if (IsKeyboardAccessoryEnabled() && + if ((IsKeyboardAccessoryEnabled() || !focus_requires_scroll_) && WebUserGestureIndicator::IsProcessingUserGesture( node.IsNull() ? nullptr : node.GetDocument().GetFrame())) { focused_node_was_last_clicked_ = true; @@ -593,6 +605,10 @@ is_secure_context_required_ = required; } +void AutofillAgent::SetFocusRequiresScroll(bool require) { + focus_requires_scroll_ = require; +} + void AutofillAgent::QueryAutofillSuggestions( const WebFormControlElement& element) { if (!element.GetDocument().GetFrame()) @@ -711,7 +727,7 @@ if (!focused_element.IsNull() && password_autofill_agent_) password_autofill_agent_->FocusedNodeHasChanged(focused_element); - if (!IsKeyboardAccessoryEnabled()) + if (!IsKeyboardAccessoryEnabled() && focus_requires_scroll_) HandleFocusChangeComplete(); } @@ -720,7 +736,7 @@ DCHECK(!node.IsNull()); focused_node_was_last_clicked_ = node.Focused(); - if (IsKeyboardAccessoryEnabled()) + if (IsKeyboardAccessoryEnabled() || !focus_requires_scroll_) HandleFocusChangeComplete(); }
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index 44810de..d5a6a9a 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -84,6 +84,7 @@ const PasswordFormFillData& form_data) override; void SetUserGestureRequired(bool required) override; void SetSecureContextRequired(bool required) override; + void SetFocusRequiresScroll(bool require) override; void ShowNotSecureWarning(const blink::WebInputElement& element); @@ -307,6 +308,9 @@ FormTracker form_tracker_; + // Whether or not we delay focus handling until scrolling occurs. + bool focus_requires_scroll_ = true; + mojo::Binding<mojom::AutofillAgent> binding_; mojom::AutofillDriverPtr autofill_driver_;
diff --git a/components/autofill/core/browser/autofill_handler.cc b/components/autofill/core/browser/autofill_handler.cc index 7c1424b..a099eb8d 100644 --- a/components/autofill/core/browser/autofill_handler.cc +++ b/components/autofill/core/browser/autofill_handler.cc
@@ -36,6 +36,18 @@ OnTextFieldDidChangeImpl(form, field, transformed_box, timestamp); } +void AutofillHandler::OnTextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) { + if (!IsValidFormData(form) || !IsValidFormFieldData(field)) + return; + + gfx::RectF transformed_box = + driver_->TransformBoundingBoxToViewportCoordinates(bounding_box); + + OnTextFieldDidScrollImpl(form, field, transformed_box); +} + void AutofillHandler::OnQueryFormFieldAutofill(int query_id, const FormData& form, const FormFieldData& field,
diff --git a/components/autofill/core/browser/autofill_handler.h b/components/autofill/core/browser/autofill_handler.h index d8f7b67..e8bdf42 100644 --- a/components/autofill/core/browser/autofill_handler.h +++ b/components/autofill/core/browser/autofill_handler.h
@@ -40,6 +40,11 @@ const gfx::RectF& bounding_box, const base::TimeTicks timestamp); + // Invoked when the textfield is scrolled. + void OnTextFieldDidScroll(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box); + // Invoked when the |form| needs to be autofilled, the |bounding_box| is // a window relative value of |field|. void OnQueryFormFieldAutofill(int query_id, @@ -113,6 +118,10 @@ const gfx::RectF& bounding_box, const base::TimeTicks timestamp) = 0; + virtual void OnTextFieldDidScrollImpl(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) = 0; + virtual void OnQueryFormFieldAutofillImpl(int query_id, const FormData& form, const FormFieldData& field,
diff --git a/components/autofill/core/browser/autofill_handler_proxy.cc b/components/autofill/core/browser/autofill_handler_proxy.cc index c36d839..fd223daa 100644 --- a/components/autofill/core/browser/autofill_handler_proxy.cc +++ b/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -29,6 +29,13 @@ provider_->OnTextFieldDidChange(this, form, field, bounding_box, timestamp); } +void AutofillHandlerProxy::OnTextFieldDidScrollImpl( + const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) { + provider_->OnTextFieldDidScroll(this, form, field, bounding_box); +} + void AutofillHandlerProxy::OnQueryFormFieldAutofillImpl( int query_id, const FormData& form,
diff --git a/components/autofill/core/browser/autofill_handler_proxy.h b/components/autofill/core/browser/autofill_handler_proxy.h index 00ea955..0a3a039 100644 --- a/components/autofill/core/browser/autofill_handler_proxy.h +++ b/components/autofill/core/browser/autofill_handler_proxy.h
@@ -50,6 +50,10 @@ const gfx::RectF& bounding_box, const base::TimeTicks timestamp) override; + void OnTextFieldDidScrollImpl(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override; + void OnQueryFormFieldAutofillImpl(int query_id, const FormData& form, const FormFieldData& field,
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 36882ea5..3f71fb7 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -244,6 +244,9 @@ const FormFieldData& field, const gfx::RectF& bounding_box, const base::TimeTicks timestamp) override; + void OnTextFieldDidScrollImpl(const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) override {} void OnQueryFormFieldAutofillImpl(int query_id, const FormData& form, const FormFieldData& field,
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index b9ef7914..0ca1183 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -756,6 +756,7 @@ switch (type) { case EMPTY_TYPE: return ""; + case NO_SERVER_DATA: case UNKNOWN_TYPE: return "unknown"; case COMPANY_NAME: @@ -803,6 +804,18 @@ bool IsExampleOf(AutofillMetrics::FieldTypeQualityMetric metric, ServerFieldType predicted_type, ServerFieldType actual_type) { + // The server can send either NO_SERVER_DATA or UNKNOWN_TYPE to indicate + // that a field is not autofillable: + // + // NO_SERVER_DATA + // => A type cannot be determined based on available data. + // UNKNOWN_TYPE + // => field is believed to not have an autofill type. + // + // Both of these are tabulated as "negative" predictions; so, to simplify + // the logic below, map them both to UNKNOWN_TYPE. + if (predicted_type == NO_SERVER_DATA) + predicted_type = UNKNOWN_TYPE; switch (metric) { case AutofillMetrics::TRUE_POSITIVE: return unknown_equivalent_types_.count(actual_type) == 0 && @@ -863,9 +876,9 @@ ServerFieldType actual_field_type = GetParam().actual_field_type; ServerFieldType predicted_type = GetParam().predicted_field_type; - VLOG(2) << "Test Case = Predicted: " - << AutofillType(predicted_type).ToString() << "; " - << "Actual: " << AutofillType(actual_field_type).ToString(); + DVLOG(2) << "Test Case = Predicted: " + << AutofillType(predicted_type).ToString() << "; " + << "Actual: " << AutofillType(actual_field_type).ToString(); // Set up our form data. FormData form; @@ -898,9 +911,10 @@ test::CreateTestFormField("Unknown", "Unknown", ValueForType(actual_field_type), "text", &field); form.fields.push_back(field); - heuristic_types.push_back(predicted_type); - server_types.push_back(predicted_type == UNKNOWN_TYPE ? NO_SERVER_DATA - : predicted_type); + heuristic_types.push_back(predicted_type == NO_SERVER_DATA ? UNKNOWN_TYPE + : predicted_type); + server_types.push_back(predicted_type); + // Resolve any field type ambiguity. if (actual_field_type == AMBIGUOUS_TYPE) { if (predicted_type == COMPANY_NAME || predicted_type == NAME_MIDDLE) @@ -937,6 +951,7 @@ by_field_type_histogram, 2 + (predicted_type != UNKNOWN_TYPE && + predicted_type != NO_SERVER_DATA && predicted_type != actual_field_type) + (unknown_equivalent_types_.count(actual_field_type) == 0)); @@ -947,8 +962,8 @@ FieldTypeCross(NAME_LAST, NAME_LAST), 1); histogram_tester.ExpectBucketCount( crossed_histogram, - FieldTypeCross((source == "Server" && predicted_type == UNKNOWN_TYPE - ? NO_SERVER_DATA + FieldTypeCross((predicted_type == NO_SERVER_DATA && source != "Server" + ? UNKNOWN_TYPE : predicted_type), actual_field_type), 1); @@ -993,7 +1008,7 @@ // (empty is not a predictable value) and we don't capture false negative // mismatches. int expected_count_for_predicted_type = - (predicted_type != UNKNOWN_TYPE && + (predicted_type != UNKNOWN_TYPE && predicted_type != NO_SERVER_DATA && metric != AutofillMetrics::FALSE_NEGATIVE_MISMATCH) ? basic_expected_count : 0; @@ -1020,10 +1035,10 @@ INSTANTIATE_TEST_CASE_P( AutofillMetricsTest, QualityMetricsTest, - testing::Values(QualityMetricsTestCase{UNKNOWN_TYPE, EMPTY_TYPE}, - QualityMetricsTestCase{UNKNOWN_TYPE, UNKNOWN_TYPE}, - QualityMetricsTestCase{UNKNOWN_TYPE, AMBIGUOUS_TYPE}, - QualityMetricsTestCase{UNKNOWN_TYPE, EMAIL_ADDRESS}, + testing::Values(QualityMetricsTestCase{NO_SERVER_DATA, EMPTY_TYPE}, + QualityMetricsTestCase{NO_SERVER_DATA, UNKNOWN_TYPE}, + QualityMetricsTestCase{NO_SERVER_DATA, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{NO_SERVER_DATA, EMAIL_ADDRESS}, QualityMetricsTestCase{EMAIL_ADDRESS, EMPTY_TYPE}, QualityMetricsTestCase{EMAIL_ADDRESS, UNKNOWN_TYPE}, QualityMetricsTestCase{EMAIL_ADDRESS, AMBIGUOUS_TYPE}, @@ -1031,7 +1046,11 @@ QualityMetricsTestCase{EMAIL_ADDRESS, COMPANY_NAME}, QualityMetricsTestCase{COMPANY_NAME, EMAIL_ADDRESS}, QualityMetricsTestCase{NAME_MIDDLE, AMBIGUOUS_TYPE}, - QualityMetricsTestCase{COMPANY_NAME, AMBIGUOUS_TYPE})); + QualityMetricsTestCase{COMPANY_NAME, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, EMPTY_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, UNKNOWN_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, EMAIL_ADDRESS})); // Ensures that metrics that measure timing some important Autofill functions // actually are recorded and retrieved.
diff --git a/components/autofill/core/browser/autofill_provider.h b/components/autofill/core/browser/autofill_provider.h index d0776bc6..edc25f92 100644 --- a/components/autofill/core/browser/autofill_provider.h +++ b/components/autofill/core/browser/autofill_provider.h
@@ -35,6 +35,11 @@ const gfx::RectF& bounding_box, const base::TimeTicks timestamp) = 0; + virtual void OnTextFieldDidScroll(AutofillHandlerProxy* handler, + const FormData& form, + const FormFieldData& field, + const gfx::RectF& bounding_box) = 0; + virtual bool OnWillSubmitForm(AutofillHandlerProxy* handler, const FormData& form, const base::TimeTicks timestamp) = 0;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 6bad5882..425a7b0 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -507,9 +507,6 @@ current_field->overall_type_prediction()); query_response_has_no_server_data &= field_type == NO_SERVER_DATA; - // UNKNOWN_TYPE is reserved for use by the client. - DCHECK_NE(field_type, UNKNOWN_TYPE); - ServerFieldType heuristic_type = field->heuristic_type(); if (heuristic_type != UNKNOWN_TYPE) heuristics_detected_fillable_field = true;
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index d6dcec11..641d9b2 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -3921,6 +3921,62 @@ EXPECT_EQ(0U, form_structure2.PossibleValues(ADDRESS_BILLING_COUNTRY).size()); } +// Tests proper resolution heuristic, server and html field types when the +// server returns NO_SERVER_DATA, UNKNOWN_TYPE, and a valid type. +TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) { + FormData form_data; + FormFieldData field; + form_data.origin = GURL("http://foo.com"); + field.form_control_type = "text"; + + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("fname"); + form_data.fields.push_back(field); + + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lname"); + form_data.fields.push_back(field); + + field.label = ASCIIToUTF16("email"); + field.name = ASCIIToUTF16("email"); + field.autocomplete_attribute = "address-level2"; + form_data.fields.push_back(field); + + FormStructure form(form_data); + form.DetermineHeuristicTypes(nullptr /* ukm_service */); + + // Setup the query response. + AutofillQueryResponseContents response; + std::string response_string; + response.add_field()->set_overall_type_prediction(UNKNOWN_TYPE); + response.add_field()->set_overall_type_prediction(NO_SERVER_DATA); + response.add_field()->set_overall_type_prediction(ADDRESS_HOME_LINE1); + ASSERT_TRUE(response.SerializeToString(&response_string)); + + // Parse the response and update the field type predictions. + std::vector<FormStructure*> forms{&form}; + FormStructure::ParseQueryResponse(response_string, forms); + ASSERT_EQ(form.field_count(), 3U); + + // Validate field 0. + EXPECT_EQ(NAME_FIRST, form.field(0)->heuristic_type()); + EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->overall_server_type()); + EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(0)->html_type()); + EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->Type().GetStorableType()); + + // Validate field 1. + EXPECT_EQ(NAME_LAST, form.field(1)->heuristic_type()); + EXPECT_EQ(NO_SERVER_DATA, form.field(1)->overall_server_type()); + EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(1)->html_type()); + EXPECT_EQ(NAME_LAST, form.field(1)->Type().GetStorableType()); + + // Validate field 2. Note: HTML_TYPE_ADDRESS_LEVEL2 -> City + EXPECT_EQ(EMAIL_ADDRESS, form.field(2)->heuristic_type()); + EXPECT_EQ(ADDRESS_HOME_LINE1, form.field(2)->overall_server_type()); + EXPECT_EQ(HTML_TYPE_ADDRESS_LEVEL2, form.field(2)->html_type()); + EXPECT_EQ(ADDRESS_HOME_CITY, form.field(2)->Type().GetStorableType()); +} + // TODO(crbug.com/578257): Add more tests for the AutofillQueryResponseContents // proto. TEST_F(FormStructureTest, ParseQueryResponse) { @@ -3994,7 +4050,7 @@ EXPECT_EQ(0U, forms[1]->field(1)->server_predictions()[0].type()); } -TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) { +TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) { FormData form; form.origin = GURL("http://foo.com"); FormFieldData field;
diff --git a/components/printing/test/BUILD.gn b/components/printing/test/BUILD.gn index aad7715..65e63db 100644 --- a/components/printing/test/BUILD.gn +++ b/components/printing/test/BUILD.gn
@@ -23,6 +23,7 @@ "//content/test:test_support", "//ipc", "//printing", + "//printing:test_support", "//skia", "//testing/gtest", "//ui/gfx/geometry",
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 09333e8..3f5bb15 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -490,7 +490,7 @@ GpuProcessHost::~GpuProcessHost() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - SendOutstandingReplies(); + SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID); if (status_ == UNKNOWN) { RunRequestGPUInfoCallbacks(gpu::GPUInfo()); @@ -681,7 +681,7 @@ // Channel is hosed, but we may not get destroyed for a while. Send // outstanding channel creation failures now so that the caller can restart // with a new process/channel without waiting. - SendOutstandingReplies(); + SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID); } return result; } @@ -875,7 +875,7 @@ cache_key.first, base::Time(), base::Time::Max(), base::Bind([] {})); } } - SendOutstandingReplies(); + SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID); RecordProcessCrash(); GpuDataManagerImpl::GetInstance()->ProcessCrashed( process_->GetTerminationStatus(true /* known_dead */, nullptr)); @@ -1111,7 +1111,7 @@ bool current_gpu_type_enabled = swiftshader_rendering_ ? gpu_enabled_ : hardware_gpu_enabled_; if (!current_gpu_type_enabled) { - SendOutstandingReplies(); + SendOutstandingReplies(EstablishChannelStatus::GPU_ACCESS_DENIED); return false; } @@ -1132,7 +1132,9 @@ return true; } -void GpuProcessHost::SendOutstandingReplies() { +void GpuProcessHost::SendOutstandingReplies( + EstablishChannelStatus failure_status) { + DCHECK_NE(failure_status, EstablishChannelStatus::SUCCESS); valid_ = false; // First send empty channel handles for all EstablishChannel requests. @@ -1140,8 +1142,7 @@ auto callback = channel_requests_.front(); channel_requests_.pop(); callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(), - gpu::GpuFeatureInfo(), - EstablishChannelStatus::GPU_HOST_INVALID); + gpu::GpuFeatureInfo(), failure_status); } while (!create_gpu_memory_buffer_requests_.empty()) {
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h index 53eec4a..5efa679 100644 --- a/content/browser/gpu/gpu_process_host.h +++ b/content/browser/gpu/gpu_process_host.h
@@ -229,7 +229,7 @@ bool LaunchGpuProcess(); - void SendOutstandingReplies(); + void SendOutstandingReplies(EstablishChannelStatus failure_status); void RunRequestGPUInfoCallbacks(const gpu::GPUInfo& gpu_info);
diff --git a/content/browser/network_service_restart_browsertest.cc b/content/browser/network_service_restart_browsertest.cc index 52901f2c..a43322d 100644 --- a/content/browser/network_service_restart_browsertest.cc +++ b/content/browser/network_service_restart_browsertest.cc
@@ -114,10 +114,18 @@ EXPECT_FALSE(network_context2.encountered_error()); } +// Flaky on Mac bots. crbug.com/793296 +#if defined(OS_MACOSX) +#define MAYBE_StoragePartitionImplGetNetworkContext \ + DISABLED_StoragePartitionImplGetNetworkContext +#else +#define MAYBE_StoragePartitionImplGetNetworkContext \ + StoragePartitionImplGetNetworkContext +#endif // Make sure |StoragePartitionImpl::GetNetworkContext()| returns valid interface // after crash. IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, - StoragePartitionImplGetNetworkContext) { + MAYBE_StoragePartitionImplGetNetworkContext) { StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( BrowserContext::GetDefaultStoragePartition( shell()->web_contents()->GetBrowserContext()));
diff --git a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc index a1f790e..96b3648 100644 --- a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc +++ b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
@@ -30,7 +30,6 @@ #include "content/shell/test_runner/web_test_runner.h" #include "content/shell/test_runner/web_view_test_proxy.h" #include "content/test/mock_webclipboard_impl.h" -#include "gin/modules/module_registry.h" #include "media/base/audio_latency.h" #include "media/base/mime_util.h" #include "media/media_features.h"
diff --git a/gin/BUILD.gn b/gin/BUILD.gn index 39bd188c..5341919 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn
@@ -30,15 +30,6 @@ "isolate_holder.cc", "modules/console.cc", "modules/console.h", - "modules/file_module_provider.cc", - "modules/file_module_provider.h", - "modules/module_registry.cc", - "modules/module_registry.h", - "modules/module_registry_observer.h", - "modules/module_runner_delegate.cc", - "modules/module_runner_delegate.h", - "modules/timer.cc", - "modules/timer.h", "object_template_builder.cc", "object_template_builder.h", "per_context_data.cc", @@ -131,20 +122,9 @@ source_set("gin_test") { testonly = true sources = [ - "test/file.cc", - "test/file.h", - "test/file_runner.cc", - "test/file_runner.h", - "test/gc.cc", - "test/gc.h", - "test/gtest.cc", - "test/gtest.h", "test/v8_test.cc", "test/v8_test.h", ] - data = [ - "test/expect.js", - ] public_deps = [ ":gin", @@ -169,13 +149,10 @@ "converter_unittest.cc", "data_object_builder_unittest.cc", "interceptor_unittest.cc", - "modules/module_registry_unittest.cc", - "modules/timer_unittest.cc", "per_context_data_unittest.cc", "shell/gin_shell_unittest.cc", "shell_runner_unittest.cc", "test/run_all_unittests.cc", - "test/run_js_tests.cc", "v8_isolate_memory_dump_provider_unittest.cc", "v8_platform_unittest.cc", "wrappable_unittest.cc", @@ -191,10 +168,7 @@ configs += [ "//v8:external_startup_data" ] data = [ - "modules/module_registry_unittests.js", "shell/hello_world.js", - "test/file_unittests.js", - "test/gtest_unittests.js", "../OWNERS", ]
diff --git a/gin/modules/console.cc b/gin/modules/console.cc index 63fc41e..8786392b 100644 --- a/gin/modules/console.cc +++ b/gin/modules/console.cc
@@ -9,41 +9,31 @@ #include "base/strings/string_util.h" #include "gin/arguments.h" #include "gin/converter.h" -#include "gin/object_template_builder.h" -#include "gin/per_isolate_data.h" -#include "gin/public/wrapper_info.h" - -using v8::ObjectTemplate; namespace gin { namespace { -void Log(Arguments* args) { +void Log(const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); std::vector<std::string> messages; - if (!args->GetRemaining(&messages)) { - args->ThrowError(); + if (!args.GetRemaining(&messages)) { + args.ThrowError(); return; } printf("%s\n", base::JoinString(messages, " ").c_str()); } -WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; - } // namespace -const char Console::kModuleName[] = "console"; +// static +void Console::Register(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> templ) { + v8::Local<v8::FunctionTemplate> log_templ = + v8::FunctionTemplate::New(isolate, Log); + log_templ->RemovePrototype(); -v8::Local<v8::Value> Console::GetModule(v8::Isolate* isolate) { - PerIsolateData* data = PerIsolateData::From(isolate); - v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); - if (templ.IsEmpty()) { - templ = ObjectTemplateBuilder(isolate) - .SetMethod("log", Log) - .Build(); - data->SetObjectTemplate(&g_wrapper_info, templ); - } - return templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); + templ->Set(StringToSymbol(isolate, "log"), log_templ); } } // namespace gin
diff --git a/gin/modules/console.h b/gin/modules/console.h index ff8061ba..4b68aa1 100644 --- a/gin/modules/console.h +++ b/gin/modules/console.h
@@ -14,8 +14,8 @@ // we'd like to evolve the API to match window.console in browsers. class GIN_EXPORT Console { public: - static const char kModuleName[]; - static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); + static void Register(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> templ); }; } // namespace gin
diff --git a/gin/modules/file_module_provider.cc b/gin/modules/file_module_provider.cc deleted file mode 100644 index 2edb6088..0000000 --- a/gin/modules/file_module_provider.cc +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/file_module_provider.h" - -#include <stddef.h> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/strings/string_split.h" -#include "base/threading/thread_task_runner_handle.h" -#include "gin/converter.h" - -namespace gin { - -namespace { - -void AttempToLoadModule(const base::WeakPtr<Runner>& runner, - const std::vector<base::FilePath>& search_paths, - const std::string& id) { - if (!runner) - return; - - std::vector<std::string> components = base::SplitString( - id, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - base::FilePath path; - for (size_t i = 0; i < components.size(); ++i) { - // TODO(abarth): Technically the path components can be UTF-8. We don't - // handle that case correctly yet. - path = path.AppendASCII(components[i]); - } - path = path.AddExtension(FILE_PATH_LITERAL("js")); - - for (size_t i = 0; i < search_paths.size(); ++i) { - std::string source; - if (!ReadFileToString(search_paths[i].Append(path), &source)) - continue; - - Runner::Scope scope(runner.get()); - runner->Run(source, id); - return; - } - LOG(ERROR) << "Failed to load module from disk: " << id; -} - -} // namespace - -FileModuleProvider::FileModuleProvider( - const std::vector<base::FilePath>& search_paths) - : search_paths_(search_paths) { -} - -FileModuleProvider::~FileModuleProvider() = default; - -void FileModuleProvider::AttempToLoadModules( - Runner* runner, const std::set<std::string>& ids) { - std::set<std::string> modules = ids; - for (std::set<std::string>::const_iterator it = modules.begin(); - it != modules.end(); ++it) { - const std::string& id = *it; - if (attempted_ids_.count(id)) - continue; - attempted_ids_.insert(id); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(AttempToLoadModule, runner->GetWeakPtr(), - search_paths_, id)); - } -} - -} // namespace gin
diff --git a/gin/modules/file_module_provider.h b/gin/modules/file_module_provider.h deleted file mode 100644 index 7c03887..0000000 --- a/gin/modules/file_module_provider.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_MODULES_FILE_MODULE_PROVIDER_H_ -#define GIN_MODULES_FILE_MODULE_PROVIDER_H_ - -#include <set> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "gin/gin_export.h" -#include "gin/runner.h" - -namespace gin { - -// FileModuleProvider knows how to load AMD modules off disk. It searches for -// modules in the directories indiciated by |search_paths|. Although we still -// read from the file system on the main thread, we'll eventually want to move -// the reads to a background thread. -class GIN_EXPORT FileModuleProvider { - public: - explicit FileModuleProvider( - const std::vector<base::FilePath>& search_paths); - ~FileModuleProvider(); - - // Searches for modules with |ids| in the file system. If found, the modules - // will be executed asynchronously by |runner|. - void AttempToLoadModules(Runner* runner, const std::set<std::string>& ids); - - private: - std::vector<base::FilePath> search_paths_; - - // We'll only search for a given module once. We remember the set of modules - // we've already looked for in |attempted_ids_|. - std::set<std::string> attempted_ids_; - - DISALLOW_COPY_AND_ASSIGN(FileModuleProvider); -}; - -} // namespace gin - -#endif // GIN_MODULES_FILE_MODULE_PROVIDER_H_
diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc deleted file mode 100644 index cf61f7d..0000000 --- a/gin/modules/module_registry.cc +++ /dev/null
@@ -1,289 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/module_registry.h" - -#include <stddef.h> -#include <stdint.h> -#include <string> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "gin/arguments.h" -#include "gin/converter.h" -#include "gin/modules/module_registry_observer.h" -#include "gin/per_context_data.h" -#include "gin/per_isolate_data.h" -#include "gin/public/wrapper_info.h" -#include "gin/runner.h" - -using v8::Context; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Isolate; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::Persistent; -using v8::StackTrace; -using v8::String; -using v8::Value; - -namespace gin { - -struct PendingModule { - PendingModule(); - ~PendingModule(); - - std::string id; - std::vector<std::string> dependencies; - Persistent<Value> factory; -}; - -PendingModule::PendingModule() = default; - -PendingModule::~PendingModule() { - factory.Reset(); -} - -namespace { - -// Key for base::SupportsUserData::Data. -const char kModuleRegistryKey[] = "ModuleRegistry"; - -struct ModuleRegistryData : public base::SupportsUserData::Data { - std::unique_ptr<ModuleRegistry> registry; -}; - -void Define(const v8::FunctionCallbackInfo<Value>& info) { - Arguments args(info); - - if (!info.Length()) - return args.ThrowTypeError("At least one argument is required."); - - std::string id; - std::vector<std::string> dependencies; - v8::Local<Value> factory; - - if (!args.PeekNext().IsEmpty() && args.PeekNext()->IsString()) - args.GetNext(&id); - if (!args.PeekNext().IsEmpty() && args.PeekNext()->IsArray()) - args.GetNext(&dependencies); - if (!args.GetNext(&factory)) - return args.ThrowError(); - - std::unique_ptr<PendingModule> pending(new PendingModule); - pending->id = id; - pending->dependencies = dependencies; - pending->factory.Reset(args.isolate(), factory); - - ModuleRegistry* registry = - ModuleRegistry::From(args.isolate()->GetCurrentContext()); - registry->AddPendingModule(args.isolate(), std::move(pending)); -} - -WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; - -Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) { - PerIsolateData* data = PerIsolateData::From(isolate); - Local<FunctionTemplate> templ = data->GetFunctionTemplate( - &g_wrapper_info); - if (templ.IsEmpty()) { - templ = FunctionTemplate::New(isolate, Define); - templ->RemovePrototype(); - data->SetFunctionTemplate(&g_wrapper_info, templ); - } - return templ; -} - -} // namespace - -ModuleRegistry::ModuleRegistry(Isolate* isolate) - : modules_(isolate, Object::New(isolate)) { -} - -ModuleRegistry::~ModuleRegistry() { - modules_.Reset(); -} - -// static -void ModuleRegistry::RegisterGlobals(Isolate* isolate, - v8::Local<ObjectTemplate> templ) { - templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate)); -} - -// static -bool ModuleRegistry::InstallGlobals(v8::Isolate* isolate, - v8::Local<v8::Object> obj) { - v8::Local<v8::Function> function; - auto maybe_function = - GetDefineTemplate(isolate)->GetFunction(isolate->GetCurrentContext()); - if (!maybe_function.ToLocal(&function)) - return false; - return SetProperty(isolate, obj, StringToSymbol(isolate, "define"), function); -} - -// static -ModuleRegistry* ModuleRegistry::From(v8::Local<Context> context) { - PerContextData* data = PerContextData::From(context); - if (!data) - return NULL; - - ModuleRegistryData* registry_data = static_cast<ModuleRegistryData*>( - data->GetUserData(kModuleRegistryKey)); - if (!registry_data) { - // PerContextData takes ownership of ModuleRegistryData. - registry_data = new ModuleRegistryData; - registry_data->registry.reset(new ModuleRegistry(context->GetIsolate())); - data->SetUserData(kModuleRegistryKey, base::WrapUnique(registry_data)); - } - return registry_data->registry.get(); -} - -void ModuleRegistry::AddObserver(ModuleRegistryObserver* observer) { - observer_list_.AddObserver(observer); -} - -void ModuleRegistry::RemoveObserver(ModuleRegistryObserver* observer) { - observer_list_.RemoveObserver(observer); -} - -void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, - v8::Local<Value> module) { - DCHECK(!id.empty()); - RegisterModule(isolate, id, module); -} - -void ModuleRegistry::AddPendingModule(Isolate* isolate, - std::unique_ptr<PendingModule> pending) { - const std::string pending_id = pending->id; - const std::vector<std::string> pending_dependencies = pending->dependencies; - AttemptToLoad(isolate, std::move(pending)); - for (auto& observer : observer_list_) - observer.OnDidAddPendingModule(pending_id, pending_dependencies); -} - -void ModuleRegistry::LoadModule(Isolate* isolate, - const std::string& id, - LoadModuleCallback callback) { - if (available_modules_.find(id) != available_modules_.end()) { - // Should we call the callback asynchronously? - callback.Run(GetModule(isolate, id)); - return; - } - waiting_callbacks_.insert(std::make_pair(id, callback)); - - for (size_t i = 0; i < pending_modules_.size(); ++i) { - if (pending_modules_[i]->id == id) - return; - } - - unsatisfied_dependencies_.insert(id); -} - -bool ModuleRegistry::RegisterModule(Isolate* isolate, - const std::string& id, - v8::Local<Value> module) { - if (id.empty() || module.IsEmpty()) - return false; - - v8::Local<Object> modules = Local<Object>::New(isolate, modules_); - if (!SetProperty(isolate, modules, StringToSymbol(isolate, id), module)) - return false; - unsatisfied_dependencies_.erase(id); - available_modules_.insert(id); - - std::pair<LoadModuleCallbackMap::iterator, LoadModuleCallbackMap::iterator> - range = waiting_callbacks_.equal_range(id); - std::vector<LoadModuleCallback> callbacks; - callbacks.reserve(waiting_callbacks_.count(id)); - for (LoadModuleCallbackMap::iterator it = range.first; it != range.second; - ++it) { - callbacks.push_back(it->second); - } - waiting_callbacks_.erase(range.first, range.second); - for (std::vector<LoadModuleCallback>::iterator it = callbacks.begin(); - it != callbacks.end(); - ++it) { - // Should we call the callback asynchronously? - it->Run(module); - } - return true; -} - -bool ModuleRegistry::CheckDependencies(PendingModule* pending) { - size_t num_missing_dependencies = 0; - size_t len = pending->dependencies.size(); - for (size_t i = 0; i < len; ++i) { - const std::string& dependency = pending->dependencies[i]; - if (available_modules_.count(dependency)) - continue; - unsatisfied_dependencies_.insert(dependency); - num_missing_dependencies++; - } - return num_missing_dependencies == 0; -} - -bool ModuleRegistry::Load(Isolate* isolate, - std::unique_ptr<PendingModule> pending) { - if (!pending->id.empty() && available_modules_.count(pending->id)) - return true; // We've already loaded this module. - - uint32_t argc = static_cast<uint32_t>(pending->dependencies.size()); - std::vector<v8::Local<Value> > argv(argc); - for (uint32_t i = 0; i < argc; ++i) - argv[i] = GetModule(isolate, pending->dependencies[i]); - - v8::Local<Value> module = Local<Value>::New(isolate, pending->factory); - - v8::Local<Function> factory; - if (ConvertFromV8(isolate, module, &factory)) { - PerContextData* data = PerContextData::From(isolate->GetCurrentContext()); - Runner* runner = data->runner(); - module = runner->Call(factory, runner->global(), argc, - argv.empty() ? NULL : &argv.front()); - if (pending->id.empty()) - ConvertFromV8(isolate, factory->GetScriptOrigin().ResourceName(), - &pending->id); - } - - return RegisterModule(isolate, pending->id, module); -} - -bool ModuleRegistry::AttemptToLoad(Isolate* isolate, - std::unique_ptr<PendingModule> pending) { - if (!CheckDependencies(pending.get())) { - pending_modules_.push_back(std::move(pending)); - return false; - } - return Load(isolate, std::move(pending)); -} - -v8::Local<v8::Value> ModuleRegistry::GetModule(v8::Isolate* isolate, - const std::string& id) { - v8::Local<Object> modules = Local<Object>::New(isolate, modules_); - v8::Local<String> key = StringToSymbol(isolate, id); - DCHECK(modules->HasOwnProperty(isolate->GetCurrentContext(), key).FromJust()); - return modules->Get(isolate->GetCurrentContext(), key).ToLocalChecked(); -} - -void ModuleRegistry::AttemptToLoadMoreModules(Isolate* isolate) { - bool keep_trying = true; - while (keep_trying) { - keep_trying = false; - PendingModuleVector pending_modules; - pending_modules.swap(pending_modules_); - for (size_t i = 0; i < pending_modules.size(); ++i) { - std::unique_ptr<PendingModule> pending(std::move(pending_modules[i])); - pending_modules[i] = NULL; - if (AttemptToLoad(isolate, std::move(pending))) - keep_trying = true; - } - } -} - -} // namespace gin
diff --git a/gin/modules/module_registry.h b/gin/modules/module_registry.h deleted file mode 100644 index c1d3a00..0000000 --- a/gin/modules/module_registry.h +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_MODULES_MODULE_REGISTRY_H_ -#define GIN_MODULES_MODULE_REGISTRY_H_ - -#include <list> -#include <map> -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "gin/gin_export.h" -#include "v8/include/v8.h" - -namespace gin { - -class ModuleRegistryObserver; -struct PendingModule; - -// This class implements the Asynchronous Module Definition (AMD) API. -// https://github.com/amdjs/amdjs-api/wiki/AMD -// -// Our implementation isn't complete yet. Missing features: -// 1) Built-in support for require, exports, and module. -// 2) Path resoltuion in module names. -// -// For these reasons, we don't have an "amd" property on the "define" -// function. The spec says we should only add that property once our -// implementation complies with the specification. -// -class GIN_EXPORT ModuleRegistry { - public: - typedef base::Callback<void (v8::Local<v8::Value>)> LoadModuleCallback; - - virtual ~ModuleRegistry(); - - static ModuleRegistry* From(v8::Local<v8::Context> context); - - static void RegisterGlobals(v8::Isolate* isolate, - v8::Local<v8::ObjectTemplate> templ); - - // Installs the necessary functions needed for modules. - // WARNING: this may execute script in the page. - static bool InstallGlobals(v8::Isolate* isolate, v8::Local<v8::Object> obj); - - void AddObserver(ModuleRegistryObserver* observer); - void RemoveObserver(ModuleRegistryObserver* observer); - - // The caller must have already entered our context. - void AddBuiltinModule(v8::Isolate* isolate, const std::string& id, - v8::Local<v8::Value> module); - - // The caller must have already entered our context. - void AddPendingModule(v8::Isolate* isolate, - std::unique_ptr<PendingModule> pending); - - void LoadModule(v8::Isolate* isolate, - const std::string& id, - LoadModuleCallback callback); - - // The caller must have already entered our context. - void AttemptToLoadMoreModules(v8::Isolate* isolate); - - const std::set<std::string>& available_modules() const { - return available_modules_; - } - - const std::set<std::string>& unsatisfied_dependencies() const { - return unsatisfied_dependencies_; - } - - private: - typedef std::vector<std::unique_ptr<PendingModule>> PendingModuleVector; - typedef std::multimap<std::string, LoadModuleCallback> LoadModuleCallbackMap; - - explicit ModuleRegistry(v8::Isolate* isolate); - - bool Load(v8::Isolate* isolate, std::unique_ptr<PendingModule> pending); - bool RegisterModule(v8::Isolate* isolate, - const std::string& id, - v8::Local<v8::Value> module); - - bool CheckDependencies(PendingModule* pending); - bool AttemptToLoad(v8::Isolate* isolate, - std::unique_ptr<PendingModule> pending); - - v8::Local<v8::Value> GetModule(v8::Isolate* isolate, const std::string& id); - - std::set<std::string> available_modules_; - std::set<std::string> unsatisfied_dependencies_; - - LoadModuleCallbackMap waiting_callbacks_; - - PendingModuleVector pending_modules_; - v8::Persistent<v8::Object> modules_; - - base::ObserverList<ModuleRegistryObserver> observer_list_; - - DISALLOW_COPY_AND_ASSIGN(ModuleRegistry); -}; - -} // namespace gin - -#endif // GIN_MODULES_MODULE_REGISTRY_H_
diff --git a/gin/modules/module_registry_observer.h b/gin/modules/module_registry_observer.h deleted file mode 100644 index 68ee4ad..0000000 --- a/gin/modules/module_registry_observer.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ -#define GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ - -#include <string> -#include <vector> - -#include "gin/gin_export.h" - -namespace gin { - -// Notified of interesting events from ModuleRegistry. -class GIN_EXPORT ModuleRegistryObserver { - public: - // Called from AddPendingModule(). |id| is the id/name of the module and - // |dependencies| this list of modules |id| depends upon. - virtual void OnDidAddPendingModule( - const std::string& id, - const std::vector<std::string>& dependencies) = 0; - - protected: - virtual ~ModuleRegistryObserver() {} -}; - -} // namespace gin - -#endif // GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ -
diff --git a/gin/modules/module_registry_unittest.cc b/gin/modules/module_registry_unittest.cc deleted file mode 100644 index 3921539..0000000 --- a/gin/modules/module_registry_unittest.cc +++ /dev/null
@@ -1,167 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/module_registry.h" - -#include <stdint.h> - -#include <memory> - -#include "base/bind.h" -#include "base/macros.h" -#include "gin/modules/module_registry_observer.h" -#include "gin/modules/module_runner_delegate.h" -#include "gin/public/context_holder.h" -#include "gin/public/isolate_holder.h" -#include "gin/shell_runner.h" -#include "gin/test/v8_test.h" -#include "v8/include/v8.h" - -namespace gin { - -namespace { - -struct TestHelper { - TestHelper(v8::Isolate* isolate) - : delegate(std::vector<base::FilePath>()), - runner(new ShellRunner(&delegate, isolate)), - scope(runner.get()) { - } - - ModuleRunnerDelegate delegate; - std::unique_ptr<ShellRunner> runner; - Runner::Scope scope; -}; - -class ModuleRegistryObserverImpl : public ModuleRegistryObserver { - public: - ModuleRegistryObserverImpl() : did_add_count_(0) {} - - void OnDidAddPendingModule( - const std::string& id, - const std::vector<std::string>& dependencies) override { - did_add_count_++; - id_ = id; - dependencies_ = dependencies; - } - - int did_add_count() { return did_add_count_; } - const std::string& id() const { return id_; } - const std::vector<std::string>& dependencies() const { return dependencies_; } - - private: - int did_add_count_; - std::string id_; - std::vector<std::string> dependencies_; - - DISALLOW_COPY_AND_ASSIGN(ModuleRegistryObserverImpl); -}; - -void NestedCallback(v8::Local<v8::Value> value) { - FAIL() << "Should not be called"; -} - -void OnModuleLoaded(TestHelper* helper, - v8::Isolate* isolate, - int64_t* counter, - v8::Local<v8::Value> value) { - ASSERT_TRUE(value->IsNumber()); - v8::Local<v8::Integer> int_value = v8::Local<v8::Integer>::Cast(value); - *counter += int_value->Value(); - ModuleRegistry::From(helper->runner->GetContextHolder()->context()) - ->LoadModule(isolate, "two", base::Bind(NestedCallback)); -} - -void OnModuleLoadedNoOp(v8::Local<v8::Value> value) { - ASSERT_TRUE(value->IsNumber()); -} - -} // namespace - -typedef V8Test ModuleRegistryTest; - -// Verifies ModuleRegistry is not available after ContextHolder has been -// deleted. -TEST_F(ModuleRegistryTest, DestroyedWithContext) { - v8::Isolate::Scope isolate_scope(instance_->isolate()); - v8::HandleScope handle_scope(instance_->isolate()); - v8::Local<v8::Context> context = v8::Context::New( - instance_->isolate(), NULL, v8::Local<v8::ObjectTemplate>()); - { - ContextHolder context_holder(instance_->isolate()); - context_holder.SetContext(context); - ModuleRegistry* registry = ModuleRegistry::From(context); - EXPECT_TRUE(registry != NULL); - } - ModuleRegistry* registry = ModuleRegistry::From(context); - EXPECT_TRUE(registry == NULL); -} - -// Verifies ModuleRegistryObserver is notified appropriately. -TEST_F(ModuleRegistryTest, ModuleRegistryObserverTest) { - TestHelper helper(instance_->isolate()); - std::string source = - "define('id', ['dep1', 'dep2'], function() {" - " return function() {};" - "});"; - - ModuleRegistryObserverImpl observer; - ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> - AddObserver(&observer); - helper.runner->Run(source, "script"); - ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> - RemoveObserver(&observer); - EXPECT_EQ(1, observer.did_add_count()); - EXPECT_EQ("id", observer.id()); - ASSERT_EQ(2u, observer.dependencies().size()); - EXPECT_EQ("dep1", observer.dependencies()[0]); - EXPECT_EQ("dep2", observer.dependencies()[1]); -} - -// Verifies that multiple LoadModule calls for the same module are handled -// correctly. -TEST_F(ModuleRegistryTest, LoadModuleTest) { - TestHelper helper(instance_->isolate()); - int64_t counter = 0; - std::string source = - "define('one', [], function() {" - " return 1;" - "});"; - - ModuleRegistry::LoadModuleCallback callback = - base::Bind(OnModuleLoaded, &helper, instance_->isolate(), &counter); - for (int i = 0; i < 3; i++) { - ModuleRegistry::From(helper.runner->GetContextHolder()->context()) - ->LoadModule(instance_->isolate(), "one", callback); - } - EXPECT_EQ(0, counter); - helper.runner->Run(source, "script"); - EXPECT_EQ(3, counter); -} - -// Verifies that explicitly loading a module that's already pending does -// not cause the ModuleRegistry's unsatisfied_dependency set to grow. -TEST_F(ModuleRegistryTest, UnsatisfiedDependenciesTest) { - TestHelper helper(instance_->isolate()); - std::string source = - "define('one', ['no_such_module'], function(nsm) {" - " return 1;" - "});"; - ModuleRegistry* registry = - ModuleRegistry::From(helper.runner->GetContextHolder()->context()); - - std::set<std::string> no_such_module_set; - no_such_module_set.insert("no_such_module"); - - // Adds one unsatisfied dependency on "no-such-module". - helper.runner->Run(source, "script"); - EXPECT_EQ(no_such_module_set, registry->unsatisfied_dependencies()); - - // Should have no effect on the unsatisfied_dependencies set. - ModuleRegistry::LoadModuleCallback callback = base::Bind(OnModuleLoadedNoOp); - registry->LoadModule(instance_->isolate(), "one", callback); - EXPECT_EQ(no_such_module_set, registry->unsatisfied_dependencies()); -} - -} // namespace gin
diff --git a/gin/modules/module_registry_unittests.js b/gin/modules/module_registry_unittests.js deleted file mode 100644 index ca70148..0000000 --- a/gin/modules/module_registry_unittests.js +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -define("module0", function() { - return { - "foo": "bar", - } -}); - -define("module2", [ - "gtest", - "module0", - "module1" - ], function(gtest, module0, module1) { - gtest.expectEqual(module0.foo, "bar", - "module0.foo is " + module0.foo); - gtest.expectFalse(module0.bar, - "module0.bar is " + module0.bar); - gtest.expectEqual(module1.baz, "qux", - "module1.baz is " + module1.baz); - gtest.expectFalse(module1.qux, - "module1.qux is " + module1.qux); - - this.result = "PASS"; -}); - -define("module1", { - "baz": "qux", -});
diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc deleted file mode 100644 index 0634fff3..0000000 --- a/gin/modules/module_runner_delegate.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/module_runner_delegate.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "gin/modules/module_registry.h" -#include "gin/object_template_builder.h" -#include "gin/public/context_holder.h" - -namespace gin { - -ModuleRunnerDelegate::ModuleRunnerDelegate( - const std::vector<base::FilePath>& search_paths) - : module_provider_(search_paths) { -} - -ModuleRunnerDelegate::~ModuleRunnerDelegate() = default; - -void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, - ModuleGetter getter) { - builtin_modules_[id] = base::Bind(getter); -} - -void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, - const ModuleGetterCallback& getter) { - builtin_modules_[id] = getter; -} - -void ModuleRunnerDelegate::AttemptToLoadMoreModules(Runner* runner) { - ModuleRegistry* registry = ModuleRegistry::From( - runner->GetContextHolder()->context()); - registry->AttemptToLoadMoreModules(runner->GetContextHolder()->isolate()); - module_provider_.AttempToLoadModules( - runner, registry->unsatisfied_dependencies()); -} - -v8::Local<v8::ObjectTemplate> ModuleRunnerDelegate::GetGlobalTemplate( - ShellRunner* runner, - v8::Isolate* isolate) { - v8::Local<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate).Build(); - ModuleRegistry::RegisterGlobals(isolate, templ); - return templ; -} - -void ModuleRunnerDelegate::DidCreateContext(ShellRunner* runner) { - ShellRunnerDelegate::DidCreateContext(runner); - - v8::Local<v8::Context> context = runner->GetContextHolder()->context(); - ModuleRegistry* registry = ModuleRegistry::From(context); - - v8::Isolate* isolate = runner->GetContextHolder()->isolate(); - - for (BuiltinModuleMap::const_iterator it = builtin_modules_.begin(); - it != builtin_modules_.end(); ++it) { - registry->AddBuiltinModule(isolate, it->first, it->second.Run(isolate)); - } -} - -void ModuleRunnerDelegate::DidRunScript(ShellRunner* runner) { - AttemptToLoadMoreModules(runner); -} - -} // namespace gin
diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h deleted file mode 100644 index f49594c..0000000 --- a/gin/modules/module_runner_delegate.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_MODULES_MODULE_RUNNER_DELEGATE_H_ -#define GIN_MODULES_MODULE_RUNNER_DELEGATE_H_ - -#include <map> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "gin/gin_export.h" -#include "gin/modules/file_module_provider.h" -#include "gin/shell_runner.h" -#include "v8/include/v8.h" - -namespace gin { - -typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate); -typedef base::Callback<v8::Local<v8::Value>(v8::Isolate*)> ModuleGetterCallback; - -// Emebedders that use AMD modules will probably want to use a RunnerDelegate -// that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders -// register built-in modules and routes module requests to FileModuleProvider. -class GIN_EXPORT ModuleRunnerDelegate : public ShellRunnerDelegate { - public: - explicit ModuleRunnerDelegate( - const std::vector<base::FilePath>& search_paths); - ~ModuleRunnerDelegate() override; - - void AddBuiltinModule(const std::string& id, ModuleGetter getter); - void AddBuiltinModule(const std::string& id, - const ModuleGetterCallback& getter); - - protected: - void AttemptToLoadMoreModules(Runner* runner); - - private: - typedef std::map<std::string, ModuleGetterCallback> BuiltinModuleMap; - - // From ShellRunnerDelegate: - v8::Local<v8::ObjectTemplate> GetGlobalTemplate( - ShellRunner* runner, - v8::Isolate* isolate) override; - void DidCreateContext(ShellRunner* runner) override; - void DidRunScript(ShellRunner* runner) override; - - BuiltinModuleMap builtin_modules_; - FileModuleProvider module_provider_; - - DISALLOW_COPY_AND_ASSIGN(ModuleRunnerDelegate); -}; - -} // namespace gin - -#endif // GIN_MODULES_MODULE_RUNNER_DELEGATE_H_
diff --git a/gin/modules/timer.cc b/gin/modules/timer.cc deleted file mode 100644 index 1f60900..0000000 --- a/gin/modules/timer.cc +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/timer.h" - -#include "base/bind.h" -#include "gin/object_template_builder.h" -#include "gin/per_context_data.h" - -namespace gin { - -namespace { - -v8::Local<v8::Private> GetHiddenPropertyName(v8::Isolate* isolate) { - return v8::Private::ForApi(isolate, gin::StringToV8(isolate, "::gin::Timer")); -} - -} // namespace - -// Timer ======================================================================= - -gin::WrapperInfo Timer::kWrapperInfo = { gin::kEmbedderNativeGin }; - -// static -Handle<Timer> Timer::Create(TimerType type, v8::Isolate* isolate, int delay_ms, - v8::Local<v8::Function> function) { - return CreateHandle(isolate, new Timer(isolate, type == TYPE_REPEATING, - delay_ms, function)); -} - -ObjectTemplateBuilder Timer::GetObjectTemplateBuilder(v8::Isolate* isolate) { - // We use Unretained() here because we directly own timer_, so we know it will - // be alive when these methods are called. - return Wrappable<Timer>::GetObjectTemplateBuilder(isolate) - .SetMethod("cancel", - base::Bind(&base::Timer::Stop, base::Unretained(&timer_))) - .SetMethod("reset", - base::Bind(&base::Timer::Reset, base::Unretained(&timer_))); -} - -Timer::Timer(v8::Isolate* isolate, bool repeating, int delay_ms, - v8::Local<v8::Function> function) - : timer_(false, repeating), - runner_(PerContextData::From( - isolate->GetCurrentContext())->runner()->GetWeakPtr()), - weak_factory_(this) { - GetWrapper(runner_->GetContextHolder()->isolate()) - .ToLocalChecked() - ->SetPrivate(isolate->GetCurrentContext(), GetHiddenPropertyName(isolate), - function) - .FromJust(); - timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), - base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr())); -} - -Timer::~Timer() = default; - -void Timer::OnTimerFired() { - // This can happen in spite of the weak callback because it is possible for - // a gin::Handle<> to keep this object alive past when the isolate it is part - // of is destroyed. - if (!runner_.get()) { - return; - } - - Runner::Scope scope(runner_.get()); - v8::Isolate* isolate = runner_->GetContextHolder()->isolate(); - - v8::Local<v8::Object> wrapper; - if (!GetWrapper(isolate).ToLocal(&wrapper)) { - return; - } - - v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( - wrapper - ->GetPrivate(runner_->GetContextHolder()->context(), - GetHiddenPropertyName(isolate)) - .ToLocalChecked()); - runner_->Call(function, v8::Undefined(isolate), 0, NULL); -} - - -// TimerModule ================================================================= - -const char TimerModule::kName[] = "timer"; -WrapperInfo TimerModule::kWrapperInfo = { kEmbedderNativeGin }; - -// static -Handle<TimerModule> TimerModule::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new TimerModule()); -} - -// static -v8::Local<v8::Value> TimerModule::GetModule(v8::Isolate* isolate) { - return Create(isolate)->GetWrapper(isolate).ToLocalChecked(); -} - -TimerModule::TimerModule() = default; - -TimerModule::~TimerModule() = default; - -ObjectTemplateBuilder TimerModule::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return Wrappable<TimerModule>::GetObjectTemplateBuilder(isolate) - .SetMethod("createOneShot", - base::Bind(&Timer::Create, Timer::TYPE_ONE_SHOT)) - .SetMethod("createRepeating", - base::Bind(&Timer::Create, Timer::TYPE_REPEATING)); -} - -} // namespace gin
diff --git a/gin/modules/timer.h b/gin/modules/timer.h deleted file mode 100644 index 1b7f613..0000000 --- a/gin/modules/timer.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_MODULES_TIMER_H_ -#define GIN_MODULES_TIMER_H_ - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "gin/gin_export.h" -#include "gin/handle.h" -#include "gin/runner.h" -#include "gin/wrappable.h" -#include "v8/include/v8.h" - -namespace gin { - -class ObjectTemplateBuilder; - -// A simple scriptable timer that can work in one-shot or repeating mode. -class GIN_EXPORT Timer : public Wrappable<Timer> { - public: - enum TimerType { - TYPE_ONE_SHOT, - TYPE_REPEATING - }; - - static WrapperInfo kWrapperInfo; - static Handle<Timer> Create(TimerType type, v8::Isolate* isolate, - int delay_ms, v8::Local<v8::Function> function); - - ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override; - - private: - Timer(v8::Isolate* isolate, bool repeating, int delay_ms, - v8::Local<v8::Function> function); - ~Timer() override; - void OnTimerFired(); - - base::Timer timer_; - base::WeakPtr<gin::Runner> runner_; - base::WeakPtrFactory<Timer> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(Timer); -}; - - -class GIN_EXPORT TimerModule : public Wrappable<TimerModule> { - public: - static const char kName[]; - static WrapperInfo kWrapperInfo; - static Handle<TimerModule> Create(v8::Isolate* isolate); - static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); - - private: - TimerModule(); - ~TimerModule() override; - - ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override; -}; - -} // namespace gin - -#endif // GIN_MODULES_TIMER_H_
diff --git a/gin/modules/timer_unittest.cc b/gin/modules/timer_unittest.cc deleted file mode 100644 index 2490d23..0000000 --- a/gin/modules/timer_unittest.cc +++ /dev/null
@@ -1,148 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/modules/timer.h" - -#include <memory> - -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "gin/handle.h" -#include "gin/object_template_builder.h" -#include "gin/public/isolate_holder.h" -#include "gin/shell_runner.h" -#include "gin/test/v8_test.h" -#include "gin/try_catch.h" -#include "gin/wrappable.h" -#include "v8/include/v8.h" - -namespace gin { - -namespace { - -class Result : public Wrappable<Result> { - public: - static WrapperInfo kWrapperInfo; - static Handle<Result> Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new Result()); - } - - int count() const { return count_; } - void set_count(int count) { count_ = count; } - - void Quit() { base::RunLoop::QuitCurrentDeprecated(); } - - private: - Result() : count_(0) { - } - - ~Result() override = default; - - ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override { - return Wrappable<Result>::GetObjectTemplateBuilder(isolate) - .SetProperty("count", &Result::count, &Result::set_count) - .SetMethod("quit", &Result::Quit); - } - - int count_; -}; - -WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin }; - -struct TestHelper { - TestHelper(v8::Isolate* isolate) - : runner(new ShellRunner(&delegate, isolate)), - scope(runner.get()), - timer_module(TimerModule::Create(isolate)), - result(Result::Create(isolate)) { - EXPECT_FALSE(runner->global().IsEmpty()); - runner->global()->Set(StringToV8(isolate, "timer"), - timer_module->GetWrapper(isolate).ToLocalChecked()); - runner->global()->Set(StringToV8(isolate, "result"), - result->GetWrapper(isolate).ToLocalChecked()); - } - - ShellRunnerDelegate delegate; - std::unique_ptr<ShellRunner> runner; - Runner::Scope scope; - Handle<TimerModule> timer_module; - Handle<Result> result; -}; - -} // namespace - -typedef V8Test TimerUnittest; - -TEST_F(TimerUnittest, OneShot) { - TestHelper helper(instance_->isolate()); - std::string source = - "timer.createOneShot(0, function() {" - " result.count++;" - "});"; - - helper.runner->Run(source, "script"); - EXPECT_EQ(0, helper.result->count()); - - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, helper.result->count()); -} - -TEST_F(TimerUnittest, OneShotCancel) { - TestHelper helper(instance_->isolate()); - std::string source = - "var t = timer.createOneShot(0, function() {" - " result.count++;" - "});" - "t.cancel()"; - - helper.runner->Run(source, "script"); - EXPECT_EQ(0, helper.result->count()); - - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0, helper.result->count()); -} - -TEST_F(TimerUnittest, Repeating) { - TestHelper helper(instance_->isolate()); - - // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create - // test case and report. - std::string source = - "var t = timer.createRepeating(0, function() {" - " result.count++;" - " if (result.count == 3) {" - " /* Cancel the timer to prevent a hang when ScopedTaskEnvironment " - " flushes main thread tasks. */" - " t.cancel();" - " result.quit();" - " }" - "});"; - - helper.runner->Run(source, "script"); - EXPECT_EQ(0, helper.result->count()); - - base::RunLoop().Run(); - EXPECT_EQ(3, helper.result->count()); -} - -TEST_F(TimerUnittest, TimerCallbackToDestroyedRunner) { - TestHelper helper(instance_->isolate()); - std::string source = - "timer.createOneShot(0, function() {" - " result.count++;" - "});"; - - helper.runner->Run(source, "script"); - EXPECT_EQ(0, helper.result->count()); - - // Destroy runner, which should destroy the timer object we created. - helper.runner.reset(NULL); - base::RunLoop().RunUntilIdle(); - - // Timer should not have run because it was deleted. - EXPECT_EQ(0, helper.result->count()); -} - -} // namespace gin
diff --git a/gin/runner.h b/gin/runner.h index a898b03..928275d5 100644 --- a/gin/runner.h +++ b/gin/runner.h
@@ -25,10 +25,6 @@ // context by creating an instance of Runner::Scope on the stack. virtual void Run(const std::string& source, const std::string& resource_name) = 0; - virtual v8::Local<v8::Value> Call(v8::Local<v8::Function> function, - v8::Local<v8::Value> receiver, - int argc, - v8::Local<v8::Value> argv[]) = 0; virtual ContextHolder* GetContextHolder() = 0; v8::Local<v8::Object> global() {
diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc index a28ca155..12c74b8 100644 --- a/gin/shell/gin_main.cc +++ b/gin/shell/gin_main.cc
@@ -18,8 +18,9 @@ #include "base/threading/thread_task_runner_handle.h" #include "gin/array_buffer.h" #include "gin/modules/console.h" -#include "gin/modules/module_runner_delegate.h" +#include "gin/object_template_builder.h" #include "gin/public/isolate_holder.h" +#include "gin/shell_runner.h" #include "gin/try_catch.h" #include "gin/v8_initializer.h" @@ -40,20 +41,20 @@ runner->Run(Load(path), path.AsUTF8Unsafe()); } -std::vector<base::FilePath> GetModuleSearchPaths() { - std::vector<base::FilePath> module_base(1); - CHECK(base::GetCurrentDirectory(&module_base[0])); - return module_base; -} - -class GinShellRunnerDelegate : public ModuleRunnerDelegate { +class GinShellRunnerDelegate : public ShellRunnerDelegate { public: - GinShellRunnerDelegate() : ModuleRunnerDelegate(GetModuleSearchPaths()) { - AddBuiltinModule(Console::kModuleName, Console::GetModule); + GinShellRunnerDelegate() {} + + v8::Local<v8::ObjectTemplate> GetGlobalTemplate( + ShellRunner* runner, + v8::Isolate* isolate) override { + v8::Local<v8::ObjectTemplate> templ = + ObjectTemplateBuilder(isolate).Build(); + gin::Console::Register(isolate, templ); + return templ; } void UnhandledException(ShellRunner* runner, TryCatch& try_catch) override { - ModuleRunnerDelegate::UnhandledException(runner, try_catch); LOG(ERROR) << try_catch.GetStackTrace(); }
diff --git a/gin/shell/hello_world.js b/gin/shell/hello_world.js index 7216fbd1..6f091000 100644 --- a/gin/shell/hello_world.js +++ b/gin/shell/hello_world.js
@@ -2,6 +2,4 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -define(["console"], function(console) { - console.log("Hello World"); -}); +log("Hello World");
diff --git a/gin/shell_runner.cc b/gin/shell_runner.cc index b98240a1..f052428 100644 --- a/gin/shell_runner.cc +++ b/gin/shell_runner.cc
@@ -5,7 +5,6 @@ #include "gin/shell_runner.h" #include "gin/converter.h" -#include "gin/modules/module_registry.h" #include "gin/per_context_data.h" #include "gin/public/context_holder.h" #include "gin/try_catch.h" @@ -76,24 +75,6 @@ Run(script); } -v8::Local<v8::Value> ShellRunner::Call(v8::Local<v8::Function> function, - v8::Local<v8::Value> receiver, - int argc, - v8::Local<v8::Value> argv[]) { - TryCatch try_catch(GetContextHolder()->isolate()); - delegate_->WillRunScript(this); - - auto maybe_result = - function->Call(GetContextHolder()->context(), receiver, argc, argv); - - delegate_->DidRunScript(this); - v8::Local<v8::Value> result; - if (!maybe_result.ToLocal(&result)) - delegate_->UnhandledException(this, try_catch); - - return result; -} - ContextHolder* ShellRunner::GetContextHolder() { return context_holder_.get(); }
diff --git a/gin/shell_runner.h b/gin/shell_runner.h index f7651f0..10c92df 100644 --- a/gin/shell_runner.h +++ b/gin/shell_runner.h
@@ -48,10 +48,6 @@ // Runner overrides: void Run(const std::string& source, const std::string& resource_name) override; - v8::Local<v8::Value> Call(v8::Local<v8::Function> function, - v8::Local<v8::Value> receiver, - int argc, - v8::Local<v8::Value> argv[]) override; ContextHolder* GetContextHolder() override; private:
diff --git a/gin/test/expect.js b/gin/test/expect.js deleted file mode 100644 index 597b5b1..0000000 --- a/gin/test/expect.js +++ /dev/null
@@ -1,299 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -define(function() { - // Equality function based on isEqual in - // Underscore.js 1.5.2 - // http://underscorejs.org - // (c) 2009-2013 Jeremy Ashkenas, - // DocumentCloud, - // and Investigative Reporters & Editors - // Underscore may be freely distributed under the MIT license. - // - function has(obj, key) { - return obj.hasOwnProperty(key); - } - function isFunction(obj) { - return typeof obj === 'function'; - } - function isArrayBufferClass(className) { - return className == '[object ArrayBuffer]' || - className.match(/\[object \w+\d+(Clamped)?Array\]/); - } - // Internal recursive comparison function for `isEqual`. - function eq(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: - // http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) - return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) - return a === b; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) - return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; - // thus, `"5"` is equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is - // performed for other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are - // compared by their millisecond representations. Note that invalid - // dates with millisecond representations of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') - return false; - // Assume equality for cyclic structures. The algorithm for detecting - // cyclic structures is adapted from ES 5.1 section 15.12.3, abstract - // operation `JO`. - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) - return bStack[length] == b; - } - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && - isFunction(bCtor) && (bCtor instanceof bCtor)) - && ('constructor' in a && 'constructor' in b)) { - return false; - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - var size = 0, result = true; - // Recursively compare Maps, objects and arrays. - if (className == '[object Array]' || isArrayBufferClass(className)) { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - if (!(result = eq(a[size], b[size], aStack, bStack))) - break; - } - } - } else if (className == '[object Map]') { - result = a.size == b.size; - if (result) { - var entries = a.entries(); - for (var e = entries.next(); result && !e.done; e = entries.next()) { - var key = e.value[0]; - var value = e.value[1]; - result = b.has(key) && eq(value, b.get(key), aStack, bStack); - } - } - } else { - // Deep compare objects. - for (var key in a) { - if (has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack))) - break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (has(b, key) && !(size--)) - break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return result; - }; - - function describe(subjects) { - var descriptions = []; - Object.getOwnPropertyNames(subjects).forEach(function(name) { - if (name === "Description") - descriptions.push(subjects[name]); - else - descriptions.push(name + ": " + JSON.stringify(subjects[name])); - }); - return descriptions.join(" "); - } - - var predicates = {}; - - predicates.toBe = function(actual, expected) { - return { - "result": actual === expected, - "message": describe({ - "Actual": actual, - "Expected": expected, - }), - }; - }; - - predicates.toEqual = function(actual, expected) { - return { - "result": eq(actual, expected, [], []), - "message": describe({ - "Actual": actual, - "Expected": expected, - }), - }; - }; - - predicates.toBeDefined = function(actual) { - return { - "result": typeof actual !== "undefined", - "message": describe({ - "Actual": actual, - "Description": "Expected a defined value", - }), - }; - }; - - predicates.toBeUndefined = function(actual) { - // Recall: undefined is just a global variable. :) - return { - "result": typeof actual === "undefined", - "message": describe({ - "Actual": actual, - "Description": "Expected an undefined value", - }), - }; - }; - - predicates.toBeNull = function(actual) { - // Recall: typeof null === "object". - return { - "result": actual === null, - "message": describe({ - "Actual": actual, - "Expected": null, - }), - }; - }; - - predicates.toBeTruthy = function(actual) { - return { - "result": !!actual, - "message": describe({ - "Actual": actual, - "Description": "Expected a truthy value", - }), - }; - }; - - predicates.toBeFalsy = function(actual) { - return { - "result": !!!actual, - "message": describe({ - "Actual": actual, - "Description": "Expected a falsy value", - }), - }; - }; - - predicates.toContain = function(actual, element) { - return { - "result": (function () { - for (var i = 0; i < actual.length; ++i) { - if (eq(actual[i], element, [], [])) - return true; - } - return false; - })(), - "message": describe({ - "Actual": actual, - "Element": element, - }), - }; - }; - - predicates.toBeLessThan = function(actual, reference) { - return { - "result": actual < reference, - "message": describe({ - "Actual": actual, - "Reference": reference, - }), - }; - }; - - predicates.toBeGreaterThan = function(actual, reference) { - return { - "result": actual > reference, - "message": describe({ - "Actual": actual, - "Reference": reference, - }), - }; - }; - - predicates.toThrow = function(actual) { - return { - "result": (function () { - if (!isFunction(actual)) - throw new TypeError; - try { - actual(); - } catch (ex) { - return true; - } - return false; - })(), - "message": "Expected function to throw", - }; - } - - function negate(predicate) { - return function() { - var outcome = predicate.apply(null, arguments); - outcome.result = !outcome.result; - return outcome; - } - } - - function check(predicate) { - return function() { - var outcome = predicate.apply(null, arguments); - if (outcome.result) - return; - throw outcome.message; - }; - } - - function Condition(actual) { - this.not = {}; - Object.getOwnPropertyNames(predicates).forEach(function(name) { - var bound = predicates[name].bind(null, actual); - this[name] = check(bound); - this.not[name] = check(negate(bound)); - }, this); - } - - return function(actual) { - return new Condition(actual); - }; -});
diff --git a/gin/test/file.cc b/gin/test/file.cc deleted file mode 100644 index 38efbb4..0000000 --- a/gin/test/file.cc +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/test/file.h" - -#include <iostream> - -#include "base/bind.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "gin/arguments.h" -#include "gin/converter.h" -#include "gin/object_template_builder.h" -#include "gin/per_isolate_data.h" -#include "gin/public/wrapper_info.h" - -using v8::ObjectTemplate; - -namespace gin { - -namespace { - -v8::Local<v8::Value> ReadFileToString(gin::Arguments* args) { - std::string filename; - if (!args->GetNext(&filename)) - return v8::Null(args->isolate()); - - const base::FilePath& path = base::FilePath::FromUTF8Unsafe(filename); - std::string contents; - if (!ReadFileToString(path, &contents)) - return v8::Null(args->isolate()); - - return gin::Converter<std::string>::ToV8(args->isolate(), contents); -} - -v8::Local<v8::Value> GetSourceRootDirectory(gin::Arguments* args) { - base::FilePath path; - if (!PathService::Get(base::DIR_SOURCE_ROOT, &path)) - return v8::Null(args->isolate()); - return gin::Converter<std::string>::ToV8(args->isolate(), - path.AsUTF8Unsafe()); -} - -v8::Local<v8::Value> GetFilesInDirectory(gin::Arguments* args) { - std::string filename; - if (!args->GetNext(&filename)) - return v8::Null(args->isolate()); - - const base::FilePath& path = base::FilePath::FromUTF8Unsafe(filename); - if (!base::DirectoryExists(path)) - return v8::Null(args->isolate()); - - std::vector<std::string> names; - base::FileEnumerator e(path, false, base::FileEnumerator::FILES); - for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) { - names.push_back(name.BaseName().AsUTF8Unsafe()); - } - - v8::Local<v8::Value> v8_names; - if (!TryConvertToV8(args->isolate(), names, &v8_names)) - return v8::Null(args->isolate()); - return v8_names; -} - -gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; - -} // namespace - -const char File::kModuleName[] = "file"; - -v8::Local<v8::Value> File::GetModule(v8::Isolate* isolate) { - gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); - v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); - if (templ.IsEmpty()) { - templ = gin::ObjectTemplateBuilder(isolate) - .SetMethod("readFileToString", ReadFileToString) - .SetMethod("getFilesInDirectory", GetFilesInDirectory) - .SetMethod("getSourceRootDirectory", GetSourceRootDirectory) - .Build(); - data->SetObjectTemplate(&g_wrapper_info, templ); - } - return templ->NewInstance(); -} - -} // namespace gin
diff --git a/gin/test/file.h b/gin/test/file.h deleted file mode 100644 index a4acd59..0000000 --- a/gin/test/file.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_TEST_FILE_H_ -#define GIN_TEST_FILE_H_ - -#include "v8/include/v8.h" - -namespace gin { - -class File { - public: - static const char kModuleName[]; - static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); -}; - -} // namespace gin - -#endif // GIN_TEST_FILE_H_ -
diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc deleted file mode 100644 index 39ece62..0000000 --- a/gin/test/file_runner.cc +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/test/file_runner.h" - -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/test/scoped_task_environment.h" -#include "base/threading/thread_task_runner_handle.h" -#include "gin/array_buffer.h" -#include "gin/converter.h" -#include "gin/modules/console.h" -#include "gin/modules/module_registry.h" -#include "gin/public/context_holder.h" -#include "gin/public/isolate_holder.h" -#include "gin/test/file.h" -#include "gin/test/gc.h" -#include "gin/test/gtest.h" -#include "gin/try_catch.h" -#include "gin/v8_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace gin { - -namespace { - -std::vector<base::FilePath> GetModuleSearchPaths() { - std::vector<base::FilePath> search_paths(2); - PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]); - PathService::Get(base::DIR_EXE, &search_paths[1]); - search_paths[1] = search_paths[1].AppendASCII("gen"); - return search_paths; -} - -} // namespace - -FileRunnerDelegate::FileRunnerDelegate() - : ModuleRunnerDelegate(GetModuleSearchPaths()) { - AddBuiltinModule(Console::kModuleName, Console::GetModule); - AddBuiltinModule(GTest::kModuleName, GTest::GetModule); - AddBuiltinModule(GC::kModuleName, GC::GetModule); - AddBuiltinModule(File::kModuleName, File::GetModule); -} - -FileRunnerDelegate::~FileRunnerDelegate() = default; - -void FileRunnerDelegate::UnhandledException(ShellRunner* runner, - TryCatch& try_catch) { - ModuleRunnerDelegate::UnhandledException(runner, try_catch); - FAIL() << try_catch.GetStackTrace(); -} - -void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, - bool run_until_idle) { - ASSERT_TRUE(base::PathExists(path)) << path.LossyDisplayName(); - std::string source; - ASSERT_TRUE(ReadFileToString(path, &source)); - - base::test::ScopedTaskEnvironment scoped_task_environment; - -#ifdef V8_USE_EXTERNAL_STARTUP_DATA - gin::V8Initializer::LoadV8Snapshot(); - gin::V8Initializer::LoadV8Natives(); -#ifdef USE_V8_CONTEXT_SNAPSHOT - gin::V8Initializer::LoadV8ContextSnapshot(); -#endif // USE_V8_CONTEXT_SNAPSHOT -#endif // V8_USE_EXTERNAL_STARTUP_DATA - - gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode, - gin::IsolateHolder::kStableV8Extras, - gin::ArrayBufferAllocator::SharedInstance()); - - gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get()); - gin::ShellRunner runner(delegate, instance.isolate()); - { - gin::Runner::Scope scope(&runner); - instance.isolate()->SetCaptureStackTraceForUncaughtExceptions(true); - runner.Run(source, path.AsUTF8Unsafe()); - - if (run_until_idle) { - base::RunLoop().RunUntilIdle(); - } else { - base::RunLoop().Run(); - } - - v8::Local<v8::Value> result = runner.global()->Get( - StringToSymbol(runner.GetContextHolder()->isolate(), "result")); - EXPECT_EQ("PASS", V8ToString(result)); - } -} - -} // namespace gin
diff --git a/gin/test/file_runner.h b/gin/test/file_runner.h deleted file mode 100644 index b20859a..0000000 --- a/gin/test/file_runner.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_TEST_FILE_RUNNER_H_ -#define GIN_TEST_FILE_RUNNER_H_ - -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "gin/modules/module_runner_delegate.h" -#include "gin/runner.h" - -namespace gin { - -// FileRunnerDelegate is a simple RunnerDelegate that's useful for running -// tests. The FileRunnerDelegate provides built-in modules for "console" and -// "gtest" that are useful when writing unit tests. -// -// TODO(abarth): Rename FileRunnerDelegate to TestRunnerDelegate. -class FileRunnerDelegate : public ModuleRunnerDelegate { - public: - FileRunnerDelegate(); - ~FileRunnerDelegate() override; - - private: - // From ModuleRunnerDelegate: - void UnhandledException(ShellRunner* runner, TryCatch& try_catch) override; - - DISALLOW_COPY_AND_ASSIGN(FileRunnerDelegate); -}; - -void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, - bool run_until_idle = true); - -} // namespace gin - -#endif // GIN_TEST_FILE_RUNNER_H_
diff --git a/gin/test/file_unittests.js b/gin/test/file_unittests.js deleted file mode 100644 index 8c25806..0000000 --- a/gin/test/file_unittests.js +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -define([ - "gin/test/expect", - "file" - ], function(expect, file) { - - function isString(x) { - return toString.call(x) === '[object String]' - } - - var rootDir = file.getSourceRootDirectory(); - expect(isString(rootDir)).toBeTruthy(); - - var noArgsNull = file.getFilesInDirectory(); - expect(noArgsNull).toBeNull(); - - var files = file.getFilesInDirectory(rootDir); - expect(Array.isArray(files)).toBeTruthy(); - - var nsdNull = file.getFilesInDirectory(rootDir + "/no_such_dir"); - expect(nsdNull).toBeNull(); - - var owners = file.readFileToString(rootDir + "/OWNERS"); - expect(isString(owners)).toBeTruthy(); - expect(owners.length).toBeGreaterThan(0); - - noArgsNull = file.readFileToString(); - expect(noArgsNull).toBeNull(); - - var nsfNull = file.readFileToString(rootDir + "/no_such_file"); - expect(nsfNull).toBeNull(); - - this.result = "PASS"; -});
diff --git a/gin/test/gc.cc b/gin/test/gc.cc deleted file mode 100644 index 4cd67e19..0000000 --- a/gin/test/gc.cc +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/test/gc.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "gin/arguments.h" -#include "gin/converter.h" -#include "gin/function_template.h" -#include "gin/object_template_builder.h" -#include "gin/per_isolate_data.h" -#include "gin/public/wrapper_info.h" -#include "gin/wrappable.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace gin { - -namespace { -WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; -} // namespace - -const char GC::kModuleName[] = "gc"; - -v8::Local<v8::Value> GC::GetModule(v8::Isolate* isolate) { - PerIsolateData* data = PerIsolateData::From(isolate); - v8::Local<v8::ObjectTemplate> templ = - data->GetObjectTemplate(&g_wrapper_info); - if (templ.IsEmpty()) { - templ = ObjectTemplateBuilder(isolate) - .SetMethod("collectGarbage", - base::Bind(&v8::Isolate::LowMemoryNotification, - base::Unretained(isolate))) - .Build(); - data->SetObjectTemplate(&g_wrapper_info, templ); - } - return templ->NewInstance(); -} - -} // namespace gin
diff --git a/gin/test/gc.h b/gin/test/gc.h deleted file mode 100644 index 25917ef..0000000 --- a/gin/test/gc.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_TEST_GC_H_ -#define GIN_TEST_GC_H_ - -#include "v8/include/v8.h" - -namespace gin { - -// This module provides bindings to the garbage collector. -class GC { - public: - static const char kModuleName[]; - static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); -}; - -} // namespace gin - -#endif // GIN_TEST_GC_H_
diff --git a/gin/test/gtest.cc b/gin/test/gtest.cc deleted file mode 100644 index 76aaf1f..0000000 --- a/gin/test/gtest.cc +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gin/test/gtest.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "gin/arguments.h" -#include "gin/converter.h" -#include "gin/function_template.h" -#include "gin/object_template_builder.h" -#include "gin/per_isolate_data.h" -#include "gin/public/wrapper_info.h" -#include "gin/wrappable.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace gin { - -namespace { - -void Fail(const std::string& description) { - FAIL() << description; -} - -void ExpectTrue(bool condition, const std::string& description) { - EXPECT_TRUE(condition) << description; -} - -void ExpectFalse(bool condition, const std::string& description) { - EXPECT_FALSE(condition) << description; -} - -void ExpectEqual(const v8::Local<v8::Value> expected, - const v8::Local<v8::Value> actual, - const std::string& description) { - EXPECT_TRUE(expected->StrictEquals(actual)) << description; -} - -WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; - -} // namespace - -const char GTest::kModuleName[] = "gtest"; - -v8::Local<v8::Value> GTest::GetModule(v8::Isolate* isolate) { - PerIsolateData* data = PerIsolateData::From(isolate); - v8::Local<v8::ObjectTemplate> templ = - data->GetObjectTemplate(&g_wrapper_info); - if (templ.IsEmpty()) { - templ = ObjectTemplateBuilder(isolate) - .SetMethod("fail", Fail) - .SetMethod("expectTrue", ExpectTrue) - .SetMethod("expectFalse", ExpectFalse) - .SetMethod("expectEqual", ExpectEqual) - .Build(); - data->SetObjectTemplate(&g_wrapper_info, templ); - } - return templ->NewInstance(); -} - -} // namespace gin
diff --git a/gin/test/gtest.h b/gin/test/gtest.h deleted file mode 100644 index 8f4332d0..0000000 --- a/gin/test/gtest.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GIN_TEST_GTEST_H_ -#define GIN_TEST_GTEST_H_ - -#include "v8/include/v8.h" - -namespace gin { - -// This module provides bindings to gtest. Most tests should use an idiomatic -// JavaScript testing API, but this module is available for tests that need a -// low-level integration with gtest. -class GTest { - public: - static const char kModuleName[]; - static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); -}; - -} // namespace gin - -#endif // GIN_TEST_GTEST_H_
diff --git a/gin/test/gtest_unittests.js b/gin/test/gtest_unittests.js deleted file mode 100644 index 1d566d5..0000000 --- a/gin/test/gtest_unittests.js +++ /dev/null
@@ -1,11 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -define(["gtest"], function(gtest) { - gtest.expectTrue(true, "true is true"); - gtest.expectFalse(false, "false is false"); - gtest.expectTrue(this, "this is " + this); - - this.result = "PASS"; -});
diff --git a/gin/test/run_js_tests.cc b/gin/test/run_js_tests.cc deleted file mode 100644 index b83dc9f2..0000000 --- a/gin/test/run_js_tests.cc +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "gin/test/file_runner.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace gin { -namespace { - -base::FilePath BasePath() { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - return path.AppendASCII("gin"); -} - -void RunTest(const base::FilePath& path) { - FileRunnerDelegate delegate; - RunTestFromFile(path, &delegate); -} - -TEST(JSTest, File) { - RunTest(BasePath() - .AppendASCII("test") - .AppendASCII("file_unittests.js")); -} - -TEST(JSTest, GTest) { - RunTest(BasePath() - .AppendASCII("test") - .AppendASCII("gtest_unittests.js")); -} - -TEST(JSTest, ModuleRegistry) { - RunTest(BasePath() - .AppendASCII("modules") - .AppendASCII("module_registry_unittests.js")); -} - -} // namespace -} // gin
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index fc999c3ff..ebefb77 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -114,7 +114,7 @@ #import "ios/chrome/browser/ui/commands/open_url_command.h" #import "ios/chrome/browser/ui/commands/show_signin_command.h" #import "ios/chrome/browser/ui/commands/start_voice_search_command.h" -#import "ios/chrome/browser/ui/download/download_manager_controller.h" +#import "ios/chrome/browser/ui/download/legacy_download_manager_controller.h" #import "ios/chrome/browser/ui/external_file_remover_factory.h" #import "ios/chrome/browser/ui/external_file_remover_impl.h" #import "ios/chrome/browser/ui/first_run/first_run_util.h" @@ -1138,7 +1138,7 @@ [[DeferredInitializationRunner sharedInstance] enqueueBlockNamed:kDeleteDownloads block:^{ - [DownloadManagerController clearDownloadsDirectory]; + [LegacyDownloadManagerController clearDownloadsDirectory]; }]; }
diff --git a/ios/chrome/browser/prerender/BUILD.gn b/ios/chrome/browser/prerender/BUILD.gn index 64f3b1c..160f1cf3 100644 --- a/ios/chrome/browser/prerender/BUILD.gn +++ b/ios/chrome/browser/prerender/BUILD.gn
@@ -62,6 +62,7 @@ ] deps = [ "//base", + "//ios/chrome/browser/ui:ui_util", "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant", "//ios/chrome/browser/ui/omnibox:omnibox_internal", "//ios/chrome/test/app:test_support",
diff --git a/ios/chrome/browser/prerender/prerender_egtest.mm b/ios/chrome/browser/prerender/prerender_egtest.mm index 5bbcbe8..98b2bc66 100644 --- a/ios/chrome/browser/prerender/prerender_egtest.mm +++ b/ios/chrome/browser/prerender/prerender_egtest.mm
@@ -10,6 +10,7 @@ #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" #import "ios/chrome/browser/ui/omnibox/truncating_attributed_label.h" +#include "ios/chrome/browser/ui/ui_util.h" #import "ios/chrome/test/app/history_test_util.h" #import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -52,6 +53,15 @@ // Test that tapping the prerendered suggestions opens it. - (void)testTapPrerenderSuggestions { + // TODO(crbug.com/793306): Re-enable the test on iOS 11 iPad once the + // alternate letters problem is fixed. + if (IsIPadIdiom()) { + if (@available(iOS 11, *)) { + EARL_GREY_TEST_DISABLED( + @"Disabled for iPad due to alternate letters educational screen."); + } + } + chrome_test_util::ClearBrowsingHistory(); [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; // Set server up.
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn index b815387..698f69f 100644 --- a/ios/chrome/browser/ui/BUILD.gn +++ b/ios/chrome/browser/ui/BUILD.gn
@@ -318,6 +318,7 @@ "//ios/chrome/browser/ui/fullscreen", "//ios/chrome/browser/ui/fullscreen:legacy_fullscreen", "//ios/chrome/browser/ui/fullscreen:new_fullscreen", + "//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui", "//ios/chrome/browser/ui/history", "//ios/chrome/browser/ui/history_popup:coordinator", "//ios/chrome/browser/ui/history_popup/requirements",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 95453e9a..7c512768 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -138,7 +138,7 @@ #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h" #import "ios/chrome/browser/ui/dialogs/dialog_presenter.h" #import "ios/chrome/browser/ui/dialogs/java_script_dialog_presenter_impl.h" -#import "ios/chrome/browser/ui/download/download_manager_controller.h" +#import "ios/chrome/browser/ui/download/legacy_download_manager_controller.h" #import "ios/chrome/browser/ui/elements/activity_overlay_coordinator.h" #import "ios/chrome/browser/ui/external_file_controller.h" #import "ios/chrome/browser/ui/external_search/external_search_coordinator.h" @@ -147,6 +147,9 @@ #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h" #import "ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.h" #import "ios/chrome/browser/ui/history_popup/requirements/tab_history_presentation.h" #import "ios/chrome/browser/ui/history_popup/tab_history_legacy_coordinator.h" @@ -397,6 +400,7 @@ CRWNativeContentProvider, CRWWebStateDelegate, DialogPresenterDelegate, + FullscreenUIElement, LegacyFullscreenControllerDelegate, InfobarContainerStateDelegate, KeyCommandsPlumbing, @@ -588,6 +592,9 @@ // The forwarder for web scroll view interation events. WebScrollViewMainContentUIForwarder* _webMainContentUIForwarder; + // The updater that adjusts the toolbar's layout for fullscreen events. + std::unique_ptr<FullscreenUIUpdater> _fullscreenUIUpdater; + // Coordinator for the External Search UI. ExternalSearchCoordinator* _externalSearchCoordinator; @@ -1183,9 +1190,10 @@ if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) { // TODO(crbug.com/790886): Use the Browser's broadcaster once Browsers are // supported. - ChromeBroadcaster* broadcaster = FullscreenControllerFactory::GetInstance() - ->GetForBrowserState(_browserState) - ->broadcaster(); + FullscreenController* fullscreenController = + FullscreenControllerFactory::GetInstance()->GetForBrowserState( + _browserState); + ChromeBroadcaster* broadcaster = fullscreenController->broadcaster(); if (_broadcasting) { _toolbarUIUpdater = [[LegacyToolbarUIUpdater alloc] initWithToolbarUI:[[ToolbarUIState alloc] init] @@ -1193,12 +1201,18 @@ webStateList:[_model webStateList]]; [_toolbarUIUpdater startUpdating]; StartBroadcastingToolbarUI(_toolbarUIUpdater.toolbarUI, broadcaster); + _mainContentUIUpdater = [[MainContentUIStateUpdater alloc] initWithState:[[MainContentUIState alloc] init]]; _webMainContentUIForwarder = [[WebScrollViewMainContentUIForwarder alloc] initWithUpdater:_mainContentUIUpdater webStateList:[_model webStateList]]; StartBroadcastingMainContentUI(self, broadcaster); + + _fullscreenUIUpdater = base::MakeUnique<FullscreenUIUpdater>(self); + fullscreenController->AddObserver(_fullscreenUIUpdater.get()); + + fullscreenController->SetWebStateList([_model webStateList]); } else { StopBroadcastingToolbarUI(broadcaster); StopBroadcastingMainContentUI(broadcaster); @@ -1207,6 +1221,9 @@ _mainContentUIUpdater = nil; [_webMainContentUIForwarder disconnect]; _webMainContentUIForwarder = nil; + fullscreenController->RemoveObserver(_fullscreenUIUpdater.get()); + _fullscreenUIUpdater = nullptr; + fullscreenController->SetWebStateList(nullptr); } } } @@ -1919,6 +1936,7 @@ [_dispatcher startDispatchingToTarget:_toolbarCoordinator forProtocol:@protocol(OmniboxFocuser)]; [_toolbarCoordinator setTabCount:[_model count]]; + [_toolbarCoordinator start]; [self updateBroadcastState]; if (_voiceSearchController) _voiceSearchController->SetDelegate( @@ -3561,8 +3579,8 @@ - (id<CRWNativeContent>)controllerForUnhandledContentAtURL:(const GURL&)URL webState: (web::WebState*)webState { - DownloadManagerController* downloadController = - [[DownloadManagerController alloc] initWithWebState:webState + LegacyDownloadManagerController* downloadController = + [[LegacyDownloadManagerController alloc] initWithWebState:webState downloadURL:URL baseViewController:self]; [downloadController start]; @@ -3587,6 +3605,80 @@ } } +#pragma mark - FullscreenUIElement methods + +- (void)updateForFullscreenProgress:(CGFloat)progress { + [self updateHeadersForFullscreenProgress:progress]; + [self updateFootersForFullscreenProgress:progress]; + [self updateContentViewTopPaddingForFullscreenProgress:progress]; +} + +- (void)updateForFullscreenEnabled:(BOOL)enabled { + if (!enabled) + [self updateForFullscreenProgress:1.0]; +} + +- (void)finishFullscreenScrollWithAnimator: + (FullscreenScrollEndAnimator*)animator { + BOOL showingToolbar = animator.finalProgress > animator.startProgress; + CGFloat finalProgress = animator.finalProgress; + // WKWebView does not re-render its content until its model layer's bounds + // have been updated at the end of the animation. If the animator is going + // to hide the toolbar, update the content view's top padding early so that + // content is correctly rendered behind the toolbar that's being animated + // away. + if (!showingToolbar) + [self updateContentViewTopPaddingForFullscreenProgress:finalProgress]; + [animator addAnimations:^{ + [self updateHeadersForFullscreenProgress:finalProgress]; + [self updateFootersForFullscreenProgress:finalProgress]; + }]; + // If the toolbar is being animated to become visible, update the content view + // top padding in the completion block so that fixed-position elements can be + // properly laid out in the new viewport. + if (showingToolbar) { + __weak FullscreenScrollEndAnimator* weakAnimator = animator; + [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { + [self updateContentViewTopPaddingForFullscreenProgress: + [weakAnimator progressForAnimatingPosition:finalPosition]]; + }]; + } +} + +#pragma mark - FullscreenUIElement helpers + +// Translates the header views up and down according to |progress|, where a +// progress of 1.0 fully shows the headers and a progress of 0.0 fully hides +// them. +- (void)updateHeadersForFullscreenProgress:(CGFloat)progress { + [self setFramesForHeaders:[self headerViews] + atOffset:(1.0 - progress) * [self toolbarHeight]]; +} + +// Translates the footer view up and down according to |progress|, where a +// progress of 1.0 fully shows the footer and a progress of 0.0 fully hides it. +- (void)updateFootersForFullscreenProgress:(CGFloat)progress { + if (![_model currentTab].isVoiceSearchResultsTab) + return; + + UIView* footerView = [self footerView]; + DCHECK(footerView); + CGRect frame = footerView.frame; + frame.origin.y = CGRectGetMaxY(footerView.superview.bounds) - + progress * CGRectGetHeight(frame); + footerView.frame = frame; +} + +// Updates the top padding of the web view proxy. This either resets the frame +// of the WKWebView or the contentInsets of the WKWebView's UIScrollView, +// depending on the the proxy's |shouldUseInsetForTopPadding| property. +- (void)updateContentViewTopPaddingForFullscreenProgress:(CGFloat)progress { + if (self.currentWebState) { + self.currentWebState->GetWebViewProxy().topContentPadding = + progress * [self toolbarHeight]; + } +} + #pragma mark - Context menu methods - (void)searchByImageAtURL:(const GURL&)url
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn index f58af832..ee62fe9a 100644 --- a/ios/chrome/browser/ui/download/BUILD.gn +++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -5,8 +5,8 @@ source_set("download") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "download_manager_controller.h", - "download_manager_controller.mm", + "legacy_download_manager_controller.h", + "legacy_download_manager_controller.mm", ] deps = [ "resources:download_manager_controller_xib", @@ -38,7 +38,7 @@ configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ - "download_manager_controller_unittest.mm", + "legacy_download_manager_controller_unittest.mm", ] deps = [ ":download",
diff --git a/ios/chrome/browser/ui/download/download_manager_controller.h b/ios/chrome/browser/ui/download/legacy_download_manager_controller.h similarity index 83% rename from ios/chrome/browser/ui/download/download_manager_controller.h rename to ios/chrome/browser/ui/download/legacy_download_manager_controller.h index 645de47..b3a129f 100644 --- a/ios/chrome/browser/ui/download/download_manager_controller.h +++ b/ios/chrome/browser/ui/download/legacy_download_manager_controller.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_CONTROLLER_H_ +#ifndef IOS_CHROME_BROWSER_UI_DOWNLOAD_LEGACY_DOWNLOAD_MANAGER_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_DOWNLOAD_LEGACY_DOWNLOAD_MANAGER_CONTROLLER_H_ #import <UIKit/UIKit.h> @@ -18,7 +18,7 @@ // the option to download it and open it in another app. This controller is // displayed when a URL is loaded that contains a file type that UIWebView // cannot display itself. -@interface DownloadManagerController +@interface LegacyDownloadManagerController : NativeContentController<UIDocumentInteractionControllerDelegate> // Initializes a controller for content from |url| using |webState| to provide @@ -39,4 +39,4 @@ @end -#endif // IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_CONTROLLER_H_ +#endif // IOS_CHROME_BROWSER_UI_DOWNLOAD_LEGACY_DOWNLOAD_MANAGER_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/download/download_manager_controller.mm b/ios/chrome/browser/ui/download/legacy_download_manager_controller.mm similarity index 98% rename from ios/chrome/browser/ui/download/download_manager_controller.mm rename to ios/chrome/browser/ui/download/legacy_download_manager_controller.mm index 3b946b6..9c87133 100644 --- a/ios/chrome/browser/ui/download/download_manager_controller.mm +++ b/ios/chrome/browser/ui/download/legacy_download_manager_controller.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/download/download_manager_controller.h" +#import "ios/chrome/browser/ui/download/legacy_download_manager_controller.h" #include <stdint.h> #include <memory> @@ -55,7 +55,7 @@ using net::URLRequestContextGetter; using net::URLRequestStatus; -@interface DownloadManagerController () +@interface LegacyDownloadManagerController () // Creates the portrait and landscape mode constraints that are switched every // time the interface is rotated. @@ -190,7 +190,7 @@ // Calls -openGoogleDriveInAppStore to allow the user to install Google Drive. - (IBAction)googleDriveButtonTapped:(id)sender; -// Cleans up this DownloadManagerController, and deletes its file from the +// Cleans up this LegacyDownloadManagerController, and deletes its file from the // downloads directory if it has been created there. - (void)dealloc; @@ -331,14 +331,14 @@ // request to get information about the file. class DownloadHeadDelegate : public URLFetcherDelegate { public: - explicit DownloadHeadDelegate(DownloadManagerController* owner) + explicit DownloadHeadDelegate(LegacyDownloadManagerController* owner) : owner_(owner) {} void OnURLFetchComplete(const URLFetcher* source) override { [owner_ onHeadFetchComplete]; }; private: - __weak DownloadManagerController* owner_; + __weak LegacyDownloadManagerController* owner_; DISALLOW_COPY_AND_ASSIGN(DownloadHeadDelegate); }; @@ -346,7 +346,7 @@ // request to download the contents of the file. class DownloadContentDelegate : public URLFetcherDelegate { public: - explicit DownloadContentDelegate(DownloadManagerController* owner) + explicit DownloadContentDelegate(LegacyDownloadManagerController* owner) : owner_(owner) {} void OnURLFetchDownloadProgress(const URLFetcher* source, int64_t current, @@ -359,13 +359,13 @@ }; private: - __weak DownloadManagerController* owner_; + __weak LegacyDownloadManagerController* owner_; DISALLOW_COPY_AND_ASSIGN(DownloadContentDelegate); }; } // namespace -@interface DownloadManagerController () { +@interface LegacyDownloadManagerController () { int _downloadManagerId; // Coordinator for displaying the alert informing the user that no application @@ -495,7 +495,7 @@ @end -@implementation DownloadManagerController +@implementation LegacyDownloadManagerController @synthesize documentContainer = _documentContainer; @synthesize progressBar = _progressBar; @@ -1057,7 +1057,7 @@ if (tabHelper) { NSString* googleDriveButtonTitle = l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_UPLOAD_TO_GOOGLE_DRIVE); - __weak DownloadManagerController* weakSelf = self; + __weak LegacyDownloadManagerController* weakSelf = self; [_alertCoordinator addItemWithTitle:googleDriveButtonTitle action:^{ [weakSelf openGoogleDriveInAppStore]; @@ -1206,12 +1206,12 @@ - (void)beginStartingContentDownload { // Ensure the directory that downloaded files are saved to exists. base::FilePath downloadsDirectoryPath; - if (![DownloadManagerController + if (![LegacyDownloadManagerController fetchDownloadsDirectoryFilePath:&downloadsDirectoryPath]) { [self displayError]; return; } - __weak DownloadManagerController* weakSelf = self; + __weak LegacyDownloadManagerController* weakSelf = self; base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindBlockArc(^{ @@ -1228,7 +1228,7 @@ return; } base::FilePath downloadsDirectoryPath; - if (![DownloadManagerController + if (![LegacyDownloadManagerController fetchDownloadsDirectoryFilePath:&downloadsDirectoryPath]) { [self displayError]; return; @@ -1270,7 +1270,7 @@ newProgressFrame.size.height - oldProgressFrame.size.height > 1) { __weak UIView* weakProgressBar = _progressBar; if (completionAnimation) { - __weak DownloadManagerController* weakSelf = self; + __weak LegacyDownloadManagerController* weakSelf = self; [UIView animateWithDuration:kProgressBarAnimationDuration animations:^{ [weakProgressBar setFrame:newProgressFrame]; @@ -1557,10 +1557,10 @@ } - (NSString*)getNetworkActivityKey { - return - [NSString stringWithFormat: - @"DownloadManagerController.NetworkActivityIndicatorKey.%d", - _downloadManagerId]; + return [NSString + stringWithFormat: + @"LegacyDownloadManagerController.NetworkActivityIndicatorKey.%d", + _downloadManagerId]; } + (BOOL)fetchDownloadsDirectoryFilePath:(base::FilePath*)path { @@ -1576,7 +1576,7 @@ FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, base::BindBlockArc(^{ base::FilePath downloadsDirectory; - if (![DownloadManagerController + if (![LegacyDownloadManagerController fetchDownloadsDirectoryFilePath:&downloadsDirectory]) { return; }
diff --git a/ios/chrome/browser/ui/download/download_manager_controller_unittest.mm b/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm similarity index 87% rename from ios/chrome/browser/ui/download/download_manager_controller_unittest.mm rename to ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm index 51eb802..a7b63a5a 100644 --- a/ios/chrome/browser/ui/download/download_manager_controller_unittest.mm +++ b/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/download/download_manager_controller.h" +#import "ios/chrome/browser/ui/download/legacy_download_manager_controller.h" #import <UIKit/UIKit.h> @@ -29,7 +29,7 @@ using net::HttpResponseHeaders; using net::URLRequestStatus; -@interface DownloadManagerController (ExposedForTesting) +@interface LegacyDownloadManagerController (ExposedForTesting) - (UIView*)documentContainer; - (UIView*)progressBar; - (UIImageView*)documentIcon; @@ -51,7 +51,7 @@ const GURL kTestURL = GURL("http://www.example.com/test_download_file.txt"); -class DownloadManagerControllerTest : public ChromeWebTest { +class LegacyDownloadManagerControllerTest : public ChromeWebTest { protected: void SetUp() override { ChromeWebTest::SetUp(); @@ -62,15 +62,15 @@ [OCMockObject niceMockForProtocol:@protocol(StoreKitLauncher)]; helper->SetLauncher(mock_launcher); _controller = - [[DownloadManagerController alloc] initWithWebState:web_state() + [[LegacyDownloadManagerController alloc] initWithWebState:web_state() downloadURL:kTestURL baseViewController:nil]; } std::unique_ptr<net::TestURLFetcherFactory> _fetcher_factory; - __strong DownloadManagerController* _controller; + __strong LegacyDownloadManagerController* _controller; }; -TEST_F(DownloadManagerControllerTest, TestXibViewConnections) { +TEST_F(LegacyDownloadManagerControllerTest, TestXibViewConnections) { EXPECT_TRUE([_controller documentContainer]); EXPECT_TRUE([_controller progressBar]); EXPECT_TRUE([_controller documentIcon]); @@ -87,7 +87,7 @@ EXPECT_TRUE([_controller googleDriveButton]); } -TEST_F(DownloadManagerControllerTest, TestStart) { +TEST_F(LegacyDownloadManagerControllerTest, TestStart) { [_controller start]; EXPECT_TRUE( [[UIApplication sharedApplication] isNetworkActivityIndicatorVisible]); @@ -96,7 +96,7 @@ EXPECT_EQ(kTestURL, fetcher->GetOriginalURL()); } -TEST_F(DownloadManagerControllerTest, TestOnHeadFetchCompleteSuccess) { +TEST_F(LegacyDownloadManagerControllerTest, TestOnHeadFetchCompleteSuccess) { [_controller start]; net::TestURLFetcher* fetcher = _fetcher_factory->GetFetcherByID(0); @@ -120,7 +120,7 @@ EXPECT_FALSE([_controller downloadButton].hidden); } -TEST_F(DownloadManagerControllerTest, TestOnHeadFetchCompleteFailure) { +TEST_F(LegacyDownloadManagerControllerTest, TestOnHeadFetchCompleteFailure) { [_controller start]; net::TestURLFetcher* fetcher = _fetcher_factory->GetFetcherByID(0);
diff --git a/ios/chrome/browser/ui/download/resources/DownloadManagerController.xib b/ios/chrome/browser/ui/download/resources/DownloadManagerController.xib index ab400a6..9e79819 100644 --- a/ios/chrome/browser/ui/download/resources/DownloadManagerController.xib +++ b/ios/chrome/browser/ui/download/resources/DownloadManagerController.xib
@@ -4,7 +4,7 @@ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> </dependencies> <objects> - <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="DownloadManagerController"> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LegacyDownloadManagerController"> <connections> <outlet property="actionBar" destination="mf4-ti-xzw" id="e6W-4V-boT"/> <outlet property="actionBarBorder" destination="vi5-3Q-93W" id="Dgb-9u-X2x"/>
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h index 01ccdfa..5d89062 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
@@ -17,6 +17,7 @@ class FullscreenMediator; class FullscreenModel; class FullscreenWebStateListObserver; +class WebStateList; // An object that observes scrolling events in the main content area and // calculates how much of the toolbar should be visible as a result. When the @@ -34,6 +35,13 @@ // ChromeBroadcaster. ChromeBroadcaster* broadcaster() { return broadcaster_; } + // The WebStateList for the Browser whose fullscreen state is managed by this + // controller. + // TODO(crbug.com/790886): Once FullscreenController is a BrowserUserData, + // remove this, as the Browser's WebStateList can be used directly rather than + // being set. + void SetWebStateList(WebStateList* web_state_list); + // Adds and removes FullscreenControllerObservers. void AddObserver(FullscreenControllerObserver* observer); void RemoveObserver(FullscreenControllerObserver* observer); @@ -56,6 +64,9 @@ // The broadcaster that drives the model. __strong ChromeBroadcaster* broadcaster_ = nil; + // The WebStateList for the Browser whose fullscreen is managed by this + // object. + WebStateList* web_state_list_ = nullptr; // The model used to calculate fullscreen state. std::unique_ptr<FullscreenModel> model_; // The bridge used to forward brodcasted UI to |model_|.
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm index 9c768f98..f6425d65 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm
@@ -34,6 +34,16 @@ FullscreenController::~FullscreenController() = default; +void FullscreenController::SetWebStateList(WebStateList* web_state_list) { + if (web_state_list_observer_) + web_state_list_observer_->Disconnect(); + web_state_list_ = web_state_list; + web_state_list_observer_ = + web_state_list_ ? base::MakeUnique<FullscreenWebStateListObserver>( + model_.get(), web_state_list_) + : nullptr; +} + void FullscreenController::AddObserver(FullscreenControllerObserver* observer) { mediator_->AddObserver(observer); } @@ -57,6 +67,8 @@ void FullscreenController::Shutdown() { mediator_->Disconnect(); + if (web_state_list_observer_) + web_state_list_observer_->Disconnect(); [broadcaster_ removeObserver:bridge_ forSelector:@selector(broadcastContentScrollOffset:)]; [broadcaster_ removeObserver:bridge_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h index 906bffa..2798f99 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
@@ -38,12 +38,11 @@ // FullscreenModelObserver: void FullscreenModelProgressUpdated(FullscreenModel* model) override; void FullscreenModelEnabledStateChanged(FullscreenModel* model) override; + void FullscreenModelScrollEventStarted(FullscreenModel* model) override; void FullscreenModelScrollEventEnded(FullscreenModel* model) override; // Stops the current scroll end animation if one is in progress. void StopAnimating(); - // Performs cleanup tasks for the animator. - void CleanUpAnimator(); // The controller. FullscreenController* controller_ = nullptr;
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm index d26f28d..df787a3 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
@@ -54,6 +54,12 @@ } } +void FullscreenMediator::FullscreenModelScrollEventStarted( + FullscreenModel* model) { + DCHECK_EQ(model_, model); + StopAnimating(); +} + void FullscreenMediator::FullscreenModelScrollEventEnded( FullscreenModel* model) { DCHECK_EQ(model_, model); @@ -61,7 +67,11 @@ animator_ = [[FullscreenScrollEndAnimator alloc] initWithStartProgress:model_->progress()]; [animator_ addCompletion:^(UIViewAnimatingPosition finalPosition) { - CleanUpAnimator(); + DCHECK(finalPosition == UIViewAnimatingPositionEnd || + finalPosition == UIViewAnimatingPositionCurrent); + model_->AnimationEndedWithProgress( + [animator_ progressForAnimatingPosition:finalPosition]); + animator_ = nil; }]; for (auto& observer : observers_) { observer.FullscreenScrollEventEnded(controller_, animator_); @@ -75,11 +85,13 @@ DCHECK_EQ(animator_.state, UIViewAnimatingStateActive); [animator_ stopAnimation:NO]; - [animator_ finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; -} -void FullscreenMediator::CleanUpAnimator() { - DCHECK(animator_); - model_->AnimationEndedWithProgress(animator_.currentProgress); - animator_ = nil; + // Property animators throw exceptions if they are deallocated in the + // UIViewAnimatingStateStopped state. Since the cleanup occurring in the + // animator's completion block occurs before |-finishAnimationAtPosition:| + // resets the state to UIViewAnimatingStateInactive, the animator is retained + // here so that it can be deallocated when reset to inactive. + FullscreenScrollEndAnimator* animator = animator_; + [animator_ finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; + animator = nil; }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model.h b/ios/chrome/browser/ui/fullscreen/fullscreen_model.h index 217ca62..46ac581 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model.h
@@ -104,6 +104,8 @@ bool scrolling_ = false; // Whether the main content is being dragged. bool dragging_ = false; + // The number of FullscreenModelObserver callbacks currently being executed. + size_t observer_callback_count_ = 0; DISALLOW_COPY_AND_ASSIGN(FullscreenModel); };
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm index 974a934e..f23c3e2 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm
@@ -14,11 +14,26 @@ #error "This file requires ARC support." #endif +namespace { +// Object that increments |counter| by 1 for its lifetime. +class ScopedIncrementer { + public: + explicit ScopedIncrementer(size_t* counter) : counter_(counter) { + ++(*counter_); + } + ~ScopedIncrementer() { --(*counter_); } + + private: + size_t* counter_; +}; +} + FullscreenModel::FullscreenModel() = default; FullscreenModel::~FullscreenModel() = default; void FullscreenModel::IncrementDisabledCounter() { if (++disabled_counter_ == 1U) { + ScopedIncrementer disabled_incrementer(&observer_callback_count_); for (auto& observer : observers_) { observer.FullscreenModelEnabledStateChanged(this); } @@ -28,6 +43,7 @@ void FullscreenModel::DecrementDisabledCounter() { DCHECK_GT(disabled_counter_, 0U); if (!--disabled_counter_) { + ScopedIncrementer enabled_incrementer(&observer_callback_count_); for (auto& observer : observers_) { observer.FullscreenModelEnabledStateChanged(this); } @@ -64,7 +80,7 @@ if (!has_base_offset()) UpdateBaseOffset(); - if (scrolling_) { + if (scrolling_ && !observer_callback_count_) { CGFloat delta = base_offset_ - y_content_offset_; SetProgress(1.0 + delta / toolbar_height_); } else { @@ -81,6 +97,7 @@ return; scrolling_ = scrolling; if (!scrolling_) { + ScopedIncrementer scroll_ended_incrementer(&observer_callback_count_); for (auto& observer : observers_) { observer.FullscreenModelScrollEventEnded(this); } @@ -95,9 +112,13 @@ if (dragging_ == dragging) return; dragging_ = dragging; - // Update the base offset when dragging occurs. - if (dragging_) + if (dragging_) { + ScopedIncrementer scroll_started_incrementer(&observer_callback_count_); + for (auto& observer : observers_) { + observer.FullscreenModelScrollEventStarted(this); + } UpdateBaseOffset(); + } } bool FullscreenModel::IsScrollViewDragging() const { @@ -110,6 +131,8 @@ if (AreCGFloatsEqual(progress_, progress)) return; progress_ = progress; + + ScopedIncrementer progress_incrementer(&observer_callback_count_); for (auto& observer : observers_) { observer.FullscreenModelProgressUpdated(this); }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h b/ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h index d966324..6d32dcb 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h
@@ -23,6 +23,9 @@ // Invoked when |model| is enabled or disabled. virtual void FullscreenModelEnabledStateChanged(FullscreenModel* model) {} + // Invoked when a scroll event being tracked by |model| has started. + virtual void FullscreenModelScrollEventStarted(FullscreenModel* model) {} + // Invoked when a scroll event being tracked by |model| has ended. virtual void FullscreenModelScrollEventEnded(FullscreenModel* model) {}
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h index c16d3669..ee508a2 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h
@@ -30,6 +30,9 @@ NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE; +// Returns the progress value corresponding with |position|. +- (CGFloat)progressForAnimatingPosition:(UIViewAnimatingPosition)position; + @end #endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm index 48daadb2..33f35a59 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm
@@ -19,6 +19,8 @@ @interface FullscreenScrollEndAnimator () { // The bezier backing the timing curve. std::unique_ptr<gfx::CubicBezier> _bezier; + // The current progress value that was recorded when the animator was stopped. + CGFloat _progressUponStopping; } @end @@ -48,11 +50,37 @@ #pragma mark Accessors - (CGFloat)currentProgress { + if (self.state == UIViewAnimatingStateStopped) + return _progressUponStopping; CGFloat interpolationFraction = _bezier->Solve(self.fractionComplete); CGFloat range = self.finalProgress - self.startProgress; return self.startProgress + interpolationFraction * range; } +#pragma mark Public + +- (CGFloat)progressForAnimatingPosition:(UIViewAnimatingPosition)position { + switch (position) { + case UIViewAnimatingPositionStart: + return self.startProgress; + case UIViewAnimatingPositionEnd: + return self.finalProgress; + case UIViewAnimatingPositionCurrent: + return self.currentProgress; + } +} + +#pragma mark UIViewAnimating + +- (void)stopAnimation:(BOOL)withoutFinishing { + // Record the progress value when transitioning from the active to stopped + // state. This allows |currentProgress| to return the correct value after + // stopping, as |fractionComplete| is reset to 0.0 for stopped animators. + if (self.state == UIViewAnimatingStateActive) + _progressUponStopping = self.currentProgress; + [super stopAnimation:withoutFinishing]; +} + #pragma mark UIViewPropertyAnimator - (BOOL)isInterruptible {
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm index a79dba5..94207252 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
@@ -20,6 +20,7 @@ DCHECK(model_); DCHECK(web_state_list_); web_state_list_->AddObserver(this); + web_state_observer_.SetWebState(web_state_list_->GetActiveWebState()); } FullscreenWebStateListObserver::~FullscreenWebStateListObserver() {
diff --git a/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm index 0d246252..e0fa789 100644 --- a/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm +++ b/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm
@@ -391,9 +391,6 @@ scrollingToOffset:0.0f]; } else { if (!visible && ![webViewProxy_ shouldUseInsetForTopPadding]) { - // The header will be hidden, so if the content view is not using the - // content inset, it is necessary to decrease the top padding, so more - // content is visible to the user. CGFloat newTopContentPadding = self.headerHeight - headerPosition; CGFloat topContentPaddingChange = [webViewProxy_ topContentPadding] - newTopContentPadding;
diff --git a/ios/chrome/browser/ui/main_content/main_content_ui_state.mm b/ios/chrome/browser/ui/main_content/main_content_ui_state.mm index 3ae7cac..76cbf2f 100644 --- a/ios/chrome/browser/ui/main_content/main_content_ui_state.mm +++ b/ios/chrome/browser/ui/main_content/main_content_ui_state.mm
@@ -85,6 +85,7 @@ - (void)scrollViewWillBeginDraggingWithGesture: (UIPanGestureRecognizer*)panGesture { self.state.dragging = YES; + self.state.decelerating = NO; self.panGesture = panGesture; }
diff --git a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm index c8d3897e..936f8d0 100644 --- a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm +++ b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
@@ -56,7 +56,9 @@ } - (void)dealloc { - [self disconnect]; + // |-disconnect| must be called before deallocation. + DCHECK(!_bridge); + DCHECK(!_proxy); } #pragma mark Accessors
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn index e0803e0..4e77cd7 100644 --- a/ios/chrome/browser/ui/omnibox/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -94,6 +94,7 @@ "//ios/chrome/browser/sessions", "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/commands", + "//ios/chrome/browser/ui/toolbar/clean:toolbar_components_ui", "//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature", "//ios/chrome/common",
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_view.h b/ios/chrome/browser/ui/omnibox/location_bar_view.h index 5e71bbfc..9960083d 100644 --- a/ios/chrome/browser/ui/omnibox/location_bar_view.h +++ b/ios/chrome/browser/ui/omnibox/location_bar_view.h
@@ -54,14 +54,12 @@ // Perform animations for expanding the omnibox. This animation can be seen on // an iPhone when the omnibox is focused. It involves sliding the leading button // out and fading its alpha. -- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)); +- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator; // Perform animations for expanding the omnibox. This animation can be seen on // an iPhone when the omnibox is defocused. It involves sliding the leading // button in and fading its alpha. -- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)); +- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator; @end
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_view.mm b/ios/chrome/browser/ui/omnibox/location_bar_view.mm index b812b9f3..523a487 100644 --- a/ios/chrome/browser/ui/omnibox/location_bar_view.mm +++ b/ios/chrome/browser/ui/omnibox/location_bar_view.mm
@@ -221,49 +221,21 @@ }]; } -- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)) { - UIView* leadingView = [self leadingButton]; - leadingView.alpha = 1; - self.leadingButtonLeadingConstraint.constant = -100; - [animator addAnimations:^{ - leadingView.alpha = 0; - - [self setNeedsLayout]; - [self layoutIfNeeded]; - }]; - - [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { - [self setLeadingButtonHidden:YES]; - [self setNeedsLayout]; - [self layoutIfNeeded]; - }]; - +- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator { + // TODO(crbug.com/791455): Due to crbug.com/774121 |self.leadingButton| is + // hidden in line 151 before the animation starts. For this reason any + // animation we try doing on |self.leadingButton| will not be visible. [self.textField addExpandOmniboxAnimations:animator]; } -- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)) { +- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator { [self setLeadingButtonHidden:NO]; - - UIView* leadingView = [self leadingButton]; - - // Move the leadingButton outside of the bounds; this constraint will be - // created from scratch when the button is shown. - self.leadingButtonLeadingConstraint.constant = leadingView.frame.size.width; - leadingView.alpha = 0; - + self.leadingButton.alpha = 0; [animator addAnimations:^{ - // Fade out the alpha and apply the constraint change above. - leadingView.alpha = 1; - [self setNeedsLayout]; + self.leadingButton.alpha = 1; + [self setLeadingButtonHidden:YES]; [self layoutIfNeeded]; - } - delayFactor:ios::material::kDuration2]; - [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { - [self setLeadingButtonHidden:NO]; }]; - [self.textField addContractOmniboxAnimations:animator]; }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h index 0f20c86..d1f1103 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h
@@ -80,12 +80,10 @@ // Called when animations added by |-animateFadeWithStyle:| can be removed. - (void)cleanUpFadeAnimations; -// New animations API. Currently are behind a flag since they require iOS 10 -// APIs to work. They replace all animations above. -- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)); -- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)); +// New animations API, currently behind clean-toolbar flag. +// They replace all animations above. +- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator; +- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator; // Initial touch on the Omnibox triggers a "pre-edit" state. The current // URL is shown without any insertion point. First character typed replaces
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm index 3e40a3e..1190d8b 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -21,6 +21,7 @@ #include "ios/chrome/browser/ui/omnibox/omnibox_util.h" #import "ios/chrome/browser/ui/reversed_animation.h" #include "ios/chrome/browser/ui/rtl_geometry.h" +#import "ios/chrome/browser/ui/toolbar/clean/toolbar_constants.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h" #import "ios/chrome/browser/ui/toolbar/public/web_toolbar_controller_constants.h" #include "ios/chrome/browser/ui/ui_util.h" @@ -301,37 +302,41 @@ [self fadeAnimationLayers]); } -- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)) { - __weak OmniboxTextFieldIOS* weakSelf = self; - [self rightView].alpha = 0; +- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator { + // Hide the rightView button so its not visibile on its initial layout + // while the expan animation is happening. + self.rightView.hidden = YES; + self.rightView.frame = [self rightViewRectForBounds:self.bounds]; + [animator addAnimations:^{ + [self layoutIfNeeded]; + [self.rightView layoutIfNeeded]; + }]; + [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { - UIView* trailingView = [weakSelf rightView]; - CGRect finalTrailingViewFrame = trailingView.frame; - trailingView.frame = - CGRectLayoutOffset(trailingView.frame, kPositionAnimationLeadingOffset); + self.rightView.hidden = NO; + self.rightView.alpha = 0; + self.rightView.frame = + CGRectLayoutOffset(self.rightView.frame, kToolbarButtonAnimationOffset); [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:0.2 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{ - trailingView.alpha = 1.0; - trailingView.frame = finalTrailingViewFrame; + self.rightView.alpha = 1.0; + self.rightView.frame = CGRectLayoutOffset( + self.rightView.frame, + -kToolbarButtonAnimationOffset); } completion:nil]; }]; } -- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator - API_AVAILABLE(ios(10.0)) { - UIView* trailingView = [self rightView]; +- (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator { [animator addAnimations:^{ - trailingView.alpha = 0; - trailingView.frame.origin = CGPointMake( - trailingView.frame.origin.x + kPositionAnimationLeadingOffset, - trailingView.frame.origin.y); + self.rightView.alpha = 0; + self.rightView.frame = + CGRectLayoutOffset(self.rightView.frame, kToolbarButtonAnimationOffset); }]; - [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { self.rightView = nil; }];
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn index 56b4a345..0d34dfd 100644 --- a/ios/chrome/browser/ui/toolbar/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -72,6 +72,9 @@ "//ios/chrome/browser/ui/colors", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/fancy_ui", + "//ios/chrome/browser/ui/fullscreen", + "//ios/chrome/browser/ui/fullscreen:new_fullscreen", + "//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui", "//ios/chrome/browser/ui/history", "//ios/chrome/browser/ui/history_popup/requirements", "//ios/chrome/browser/ui/keyboard",
diff --git a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn index 54ea7da..38f83f8 100644 --- a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
@@ -33,6 +33,8 @@ "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators", + "//ios/chrome/browser/ui/fullscreen", + "//ios/chrome/browser/ui/fullscreen:new_fullscreen", "//ios/chrome/browser/ui/history_popup/requirements", "//ios/chrome/browser/ui/omnibox", "//ios/chrome/browser/ui/omnibox:omnibox_internal", @@ -69,6 +71,7 @@ "//ios/chrome/browser/ui/activity_services/requirements", "//ios/chrome/browser/ui/bubble", "//ios/chrome/browser/ui/commands", + "//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui", "//ios/chrome/browser/ui/history_popup/requirements", "//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/voice",
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm index 3a1181c..d8aaf95 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -7,6 +7,7 @@ #import <CoreLocation/CoreLocation.h> #include "base/mac/foundation_util.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" @@ -20,6 +21,10 @@ #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" #include "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h" #include "ios/chrome/browser/ui/omnibox/location_bar_controller.h" #include "ios/chrome/browser/ui/omnibox/location_bar_controller_impl.h" #include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h" @@ -58,6 +63,8 @@ @interface ToolbarCoordinator ()<LocationBarDelegate, OmniboxPopupPositioner> { std::unique_ptr<LocationBarControllerImpl> _locationBar; std::unique_ptr<OmniboxPopupViewIOS> _popupView; + // Observer that updates |toolbarViewController| for fullscreen events. + std::unique_ptr<FullscreenControllerObserver> _fullscreenObserver; } // The View Controller managed by this coordinator. @@ -177,6 +184,14 @@ self.toolbarViewController.locationBarView = self.locationBarView; self.toolbarViewController.dispatcher = self.dispatcher; + if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) { + _fullscreenObserver = + base::MakeUnique<FullscreenUIUpdater>(self.toolbarViewController); + FullscreenControllerFactory::GetInstance() + ->GetForBrowserState(self.browserState) + ->AddObserver(_fullscreenObserver.get()); + } + DCHECK(self.toolbarViewController.toolsMenuButton); self.toolsMenuButtonObserverBridge = [[ToolsMenuButtonObserverBridge alloc] initWithModel:ReadingListModelFactory::GetForBrowserState( @@ -202,6 +217,13 @@ _locationBar.reset(); self.locationBarView = nil; [self stopObservingTTSNotifications]; + + if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) { + FullscreenControllerFactory::GetInstance() + ->GetForBrowserState(self.browserState) + ->RemoveObserver(_fullscreenObserver.get()); + _fullscreenObserver = nullptr; + } } #pragma mark - Public
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h index f29bc53..0fa0458 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
@@ -9,6 +9,7 @@ #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h" #import "ios/chrome/browser/ui/toolbar/clean/toolbar_consumer.h" @protocol ApplicationCommands; @@ -22,6 +23,7 @@ @interface ToolbarViewController : UIViewController<ActivityServicePositioner, BubbleViewAnchorPointProvider, + FullscreenUIElement, ToolbarConsumer> - (instancetype)initWithDispatcher:
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm index a809e05..526ff58 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -10,6 +10,7 @@ #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/history_popup_commands.h" #import "ios/chrome/browser/ui/commands/start_voice_search_command.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h" #include "ios/chrome/browser/ui/rtl_geometry.h" #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button.h" #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h" @@ -141,13 +142,28 @@ // the StackView. self.contractButton.hidden = NO; self.contractButton.alpha = 0; + + [UIViewPropertyAnimator + runningPropertyAnimatorWithDuration:ios::material::kDuration2 + delay:0 + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + [self + setHorizontalTranslationOffset: + kToolbarButtonAnimationOffset + forButtons: + self.leadingStackViewButtons]; + [self + setHorizontalTranslationOffset: + -kToolbarButtonAnimationOffset + forButtons: + self.trailingStackViewButtons]; + [self setAllVisibleToolbarButtonsOpacity:0]; + } + completion:nil]; + [animator addAnimations:^{ [self.view layoutIfNeeded]; - [self setHorizontalTranslationOffset:-kToolbarButtonAnimationOffset - forButtons:self.leadingStackViewButtons]; - [self setHorizontalTranslationOffset:kToolbarButtonAnimationOffset - forButtons:self.trailingStackViewButtons]; - [self setAllVisibleToolbarButtonsOpacity:0]; }]; // When the locationBarContainer has been expanded the Contract button will // fade in. @@ -356,35 +372,48 @@ constraintEqualToConstant:kToolbarShadowHeight], ]]; - // Stack views directly in view constraints. Main StackViews. + // Stack views constraints. // Layout: |[leadingStackView]-[locationBarContainer]-[trailingStackView]|. + // Safe Area constraints. CGFloat leadingMargin = IsIPadIdiom() ? kLeadingMarginIPad : 0; UILayoutGuide* viewSafeAreaGuide = SafeAreaLayoutGuideForView(self.view); - NSArray* stackViewRegularConstraints = @[ + [NSLayoutConstraint activateConstraints:@[ [self.leadingStackView.leadingAnchor constraintEqualToAnchor:viewSafeAreaGuide.leadingAnchor constant:leadingMargin], [self.trailingStackView.trailingAnchor constraintEqualToAnchor:viewSafeAreaGuide.trailingAnchor] - ]; + ]]; + // Stackviews and locationBar Spacing constraints. These will be disabled when + // expanding the omnibox. + NSArray<NSLayoutConstraint*>* stackViewSpacingConstraint = [NSLayoutConstraint + constraintsWithVisualFormat: + @"H:[leadingStack]-(spacing)-[locationBar]-(spacing)-[trailingStack]" + options:0 + metrics:@{ + @"spacing" : @(kHorizontalMargin) + } + views:@{ + @"leadingStack" : self.leadingStackView, + @"locationBar" : self.locationBarContainer, + @"trailingStack" : self.trailingStackView + }]; [self.regularToolbarConstraints - addObjectsFromArray:stackViewRegularConstraints]; - [NSLayoutConstraint activateConstraints:stackViewRegularConstraints]; + addObjectsFromArray:stackViewSpacingConstraint]; + // Vertical constraints. + [NSLayoutConstraint activateConstraints:stackViewSpacingConstraint]; ApplyVisualConstraintsWithMetrics( @[ - @"H:[leadingStack]-(spacing)-[locationBar]-(spacing)-[trailingStack]", @"V:[leadingStack(height)]-(margin)-|", @"V:[trailingStack(height)]-(margin)-|" ], @{ @"leadingStack" : self.leadingStackView, - @"locationBar" : self.locationBarContainer, @"trailingStack" : self.trailingStackView }, @{ @"height" : @(kToolbarHeight - 2 * kButtonVerticalMargin), @"margin" : @(kButtonVerticalMargin), - @"spacing" : @(kHorizontalMargin) }); // LocationBarContainer constraints. @@ -752,6 +781,27 @@ toView:self.toolsMenuButton.window]; } +#pragma mark - FullscreenUIElement + +- (void)updateForFullscreenProgress:(CGFloat)progress { + self.leadingStackView.alpha = progress; + self.locationBarContainer.alpha = progress; + self.trailingStackView.alpha = progress; +} + +- (void)updateForFullscreenEnabled:(BOOL)enabled { + if (!enabled) + [self updateForFullscreenProgress:1.0]; +} + +- (void)finishFullscreenScrollWithAnimator: + (FullscreenScrollEndAnimator*)animator { + CGFloat finalProgress = animator.finalProgress; + [animator addAnimations:^() { + [self updateForFullscreenProgress:finalProgress]; + }]; +} + #pragma mark - Helper Methods // Updates all Buttons visibility to match any recent WebState change.
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h index 6eb62c48..e42d540f 100644 --- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h +++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h
@@ -9,6 +9,7 @@ #import "ios/chrome/browser/chrome_coordinator.h" #import "ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h" #import "ios/chrome/browser/ui/ntp/incognito_view_controller_delegate.h" #import "ios/chrome/browser/ui/side_swipe/side_swipe_toolbar_interacting.h" #import "ios/chrome/browser/ui/toolbar/omnibox_focuser.h" @@ -37,7 +38,8 @@ ActivityServicePositioner, QRScannerResultLoading, BubbleViewAnchorPointProvider, - ToolsMenuPresentationProvider> + ToolsMenuPresentationProvider, + FullscreenUIElement> - (void)setToolsMenuIsVisibleForToolsMenuButton:(BOOL)isVisible; - (void)start;
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm index 70c978e..b169e67 100644 --- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
@@ -4,7 +4,13 @@ #import "ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h" +#include "base/memory/ptr_util.h" +#import "ios/chrome/browser/tabs/tab_model.h" #import "ios/chrome/browser/ui/commands/toolbar_commands.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h" #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_updater.h" #import "ios/chrome/browser/ui/toolbar/omnibox_focuser.h" #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h" @@ -19,6 +25,8 @@ @interface LegacyToolbarCoordinator () { // Coordinator for the tools menu UI. ToolsMenuCoordinator* _toolsMenuCoordinator; + // The fullscreen updater. + std::unique_ptr<FullscreenUIUpdater> _fullscreenUpdater; } @property(nonatomic, strong) id<Toolbar> toolbarController; @@ -54,7 +62,24 @@ } return self; } + +- (void)start { + if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) { + _fullscreenUpdater = + base::MakeUnique<FullscreenUIUpdater>(self.toolbarController); + FullscreenControllerFactory::GetInstance() + ->GetForBrowserState(self.tabModel.browserState) + ->AddObserver(_fullscreenUpdater.get()); + } +} + - (void)stop { + if (base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) { + FullscreenControllerFactory::GetInstance() + ->GetForBrowserState(self.tabModel.browserState) + ->RemoveObserver(_fullscreenUpdater.get()); + _fullscreenUpdater = nullptr; + } self.toolbarController = nil; }
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm index 72a0d01..79e9a40 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
@@ -183,6 +183,21 @@ anchorPointForToolsMenuButton:direction]; } +#pragma mark - FullscreenUIElement + +// FullscreenUIElements in this adapter are no-ops. ToolbarCoordinator updates +// its view controller's UI for fullscreen events. + +- (void)updateForFullscreenProgress:(CGFloat)progress { +} + +- (void)updateForFullscreenEnabled:(BOOL)enabled { +} + +- (void)finishFullscreenScrollWithAnimator: + (FullscreenScrollEndAnimator*)animator { +} + #pragma mark - ToolsMenuPresentationProvider - (UIButton*)presentingButtonForToolsMenuCoordinator:
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.h b/ios/chrome/browser/ui/toolbar/toolbar_controller.h index 31ce060..11f8de6 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_controller.h +++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.h
@@ -10,6 +10,7 @@ #import "base/mac/scoped_nsobject.h" #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h" #import "ios/chrome/browser/ui/toolbar/legacy_toolbar_view.h" #import "ios/chrome/browser/ui/toolbar/public/abstract_toolbar.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h" @@ -25,9 +26,10 @@ // buttons (forwarding to the delegate). This is not intended to be used // on its own, but to be subclassed by more specific toolbars that provide // more buttons in the empty space. -@interface ToolbarController : UIViewController<ActivityServicePositioner, +@interface ToolbarController : UIViewController<AbstractToolbar, + ActivityServicePositioner, BubbleViewAnchorPointProvider, - AbstractToolbar, + FullscreenUIElement, ToolsMenuPresentationProvider> // The top-level toolbar view.
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm index 3974f40c..9a505e6 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -18,6 +18,7 @@ #include "ios/chrome/browser/ui/bubble/bubble_util.h" #import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h" #import "ios/chrome/browser/ui/image_util.h" #import "ios/chrome/browser/ui/reversed_animation.h" #include "ios/chrome/browser/ui/rtl_geometry.h" @@ -165,6 +166,7 @@ contentView_ = [[UIView alloc] initWithFrame:viewFrame]; contentView_.translatesAutoresizingMaskIntoConstraints = NO; + contentView_.layer.allowsGroupOpacity = YES; [self.view addSubview:contentView_]; NSLayoutConstraint* safeAreaLeading = nil; NSLayoutConstraint* safeAreaTrailing = nil; @@ -757,6 +759,25 @@ toView:toolsMenuButton_.window]; } +#pragma mark - FullscreenUIElement + +- (void)updateForFullscreenProgress:(CGFloat)progress { + self.contentView.alpha = progress; +} + +- (void)updateForFullscreenEnabled:(BOOL)enabled { + if (!enabled) + [self updateForFullscreenProgress:1.0]; +} + +- (void)finishFullscreenScrollWithAnimator: + (FullscreenScrollEndAnimator*)animator { + CGFloat finalProgress = animator.finalProgress; + [animator addAnimations:^() { + [self updateForFullscreenProgress:finalProgress]; + }]; +} + #pragma mark - CAAnimationDelegate // WebToolbarController conforms to CAAnimationDelegate. - (void)animationDidStart:(CAAnimation*)anim {
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm index d5aaabc87..2959f54d 100644 --- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm +++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -44,6 +44,7 @@ #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/external_search_commands.h" #import "ios/chrome/browser/ui/commands/start_voice_search_command.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" #import "ios/chrome/browser/ui/image_util.h" #include "ios/chrome/browser/ui/omnibox/location_bar_controller.h" #include "ios/chrome/browser/ui/omnibox/location_bar_controller_impl.h" @@ -527,7 +528,8 @@ [self startObservingTTSNotifications]; - [self.view setDelegate:self]; + if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) + [self.view setDelegate:self]; if (idiom == IPHONE_IDIOM) { [[self stackButton] addTarget:dispatcher
diff --git a/ios/web/web_state/ui/crw_web_view_content_view.mm b/ios/web/web_state/ui/crw_web_view_content_view.mm index 4fc5200..c0b8802 100644 --- a/ios/web/web_state/ui/crw_web_view_content_view.mm +++ b/ios/web/web_state/ui/crw_web_view_content_view.mm
@@ -5,6 +5,8 @@ #import "ios/web/public/web_state/ui/crw_web_view_content_view.h" #import <WebKit/WebKit.h> +#include <cmath> +#include <limits> #include "base/logging.h" @@ -116,30 +118,31 @@ } - (void)setTopContentPadding:(CGFloat)newTopPadding { - if (!self.shouldUseInsetForTopPadding) { - if (_topContentPadding != newTopPadding) { - // Update the content offset of the scroll view to match the padding - // that will be included in the frame. - CGFloat paddingChange = newTopPadding - _topContentPadding; - CGPoint contentOffset = [_scrollView contentOffset]; - contentOffset.y += paddingChange; - [_scrollView setContentOffset:contentOffset]; - _topContentPadding = newTopPadding; - // Update web view frame immediately to make |topContentPadding| - // animatable. - [self updateWebViewFrame]; - // Setting WKWebView frame can mistakenly reset contentOffset. Change it - // back to the initial value if necessary. - // TODO(crbug.com/645857): Remove this workaround once WebKit bug is - // fixed. - if ([_scrollView contentOffset].y != contentOffset.y) { - [_scrollView setContentOffset:contentOffset]; - } - } - } else { + CGFloat delta = std::fabs(_topContentPadding - newTopPadding); + if (delta <= std::numeric_limits<CGFloat>::epsilon()) + return; + if (self.shouldUseInsetForTopPadding) { UIEdgeInsets inset = [_scrollView contentInset]; inset.top = newTopPadding; [_scrollView setContentInset:inset]; + } else { + // Update the content offset of the scroll view to match the padding + // that will be included in the frame. + CGFloat paddingChange = newTopPadding - _topContentPadding; + CGPoint contentOffset = [_scrollView contentOffset]; + contentOffset.y += paddingChange; + [_scrollView setContentOffset:contentOffset]; + _topContentPadding = newTopPadding; + // Update web view frame immediately to make |topContentPadding| + // animatable. + [self updateWebViewFrame]; + // Setting WKWebView frame can mistakenly reset contentOffset. Change it + // back to the initial value if necessary. + // TODO(crbug.com/645857): Remove this workaround once WebKit bug is + // fixed. + if ([_scrollView contentOffset].y != contentOffset.y) { + [_scrollView setContentOffset:contentOffset]; + } } }
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index 0d566da4..6bdf43ed 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -150,6 +150,12 @@ ~ContainerURLRequestContext() override { #if BUILDFLAG(ENABLE_REPORTING) + // Destroy the NetworkErrorLoggingDelegate so that destroying the + // ReportingService (which might abort in-flight URLRequests, generating + // network errors) won't recursively try to queue more network error + // reports. + storage_.set_network_error_logging_delegate(nullptr); + // Destroy the ReportingService before the rest of the URLRequestContext, so // it cancels any pending requests it may have. storage_.set_reporting_service(nullptr);
diff --git a/printing/BUILD.gn b/printing/BUILD.gn index 71ea5f6..086afa4 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn
@@ -33,12 +33,6 @@ "backend/printing_info_win.h", "emf_win.cc", "emf_win.h", - "image.cc", - "image.h", - "image_android.cc", - "image_linux.cc", - "image_mac.cc", - "image_win.cc", "metafile.cc", "metafile.h", "metafile_skia_wrapper.cc", @@ -242,10 +236,6 @@ "pdf_transform.h", ] } - - if (is_fuchsia) { - sources += [ "image_fuchsia.cc" ] - } } static_library("test_support") { @@ -253,12 +243,25 @@ sources = [ "backend/test_print_backend.cc", "backend/test_print_backend.h", + "image.cc", + "image.h", + "image_android.cc", + "image_linux.cc", + "image_mac.cc", + "image_win.cc", ] + if (is_fuchsia) { + sources += [ "image_fuchsia.cc" ] + } + public_deps = [ "//printing", + "//ui/gfx/geometry", ] deps = [ "//base", + "//skia", + "//ui/gfx", ] }
diff --git a/printing/image.h b/printing/image.h index 0245185f..13ac4d5 100644 --- a/printing/image.h +++ b/printing/image.h
@@ -12,7 +12,6 @@ #include <vector> #include "base/logging.h" -#include "printing/printing_export.h" #include "ui/gfx/geometry/size.h" namespace base { @@ -25,7 +24,7 @@ // Lightweight raw-bitmap management. The image, once initialized, is immutable. // The main purpose is testing image contents. -class PRINTING_EXPORT Image { +class Image { public: // Creates the image from the metafile. Deduces bounds based on bounds in // metafile. If loading fails size().IsEmpty() will be true.
diff --git a/printing/image_android.cc b/printing/image_android.cc index 544cf07..2ae4c3a 100644 --- a/printing/image_android.cc +++ b/printing/image_android.cc
@@ -7,6 +7,7 @@ namespace printing { bool Image::LoadMetafile(const Metafile& metafile) { + NOTIMPLEMENTED(); return false; }
diff --git a/printing/image_linux.cc b/printing/image_linux.cc index d89c4e9..6ccb2139 100644 --- a/printing/image_linux.cc +++ b/printing/image_linux.cc
@@ -7,6 +7,7 @@ namespace printing { bool Image::LoadMetafile(const Metafile& metafile) { + NOTIMPLEMENTED(); return false; }
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 0a72917..74c59ef 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1150,6 +1150,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "ozone_x11_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "pdf_unittests" }, {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 689ae0a..c69ff89 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -834,6 +834,10 @@ "label": "//ui/ozone/gl:ozone_gl_unittests", "type": "console_test_launcher", }, + "ozone_x11_unittests": { + "label": "//ui/ozone:ozone_x11_unittests", + "type": "windowed_test_launcher", + }, "pdf_fuzzers": { "label": "//pdf/pdfium/fuzzers:pdf_fuzzers", "type": "additional_compile_target",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 03dbaa6b..21e9ccd 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -477,6 +477,7 @@ ], }, 'ozone_unittests': {}, + 'ozone_x11_unittests': {}, 'views_mus_unittests': {}, 'views_mus_interactive_ui_tests': {}, 'viz_content_browsertests': {
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index a6bf57d..fe725b46 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -42809,6 +42809,18 @@ {} ] ], + "css/css-multicol/multicol-gap-fraction-002.html": [ + [ + "/css/css-multicol/multicol-gap-fraction-002.html", + [ + [ + "/css/reference/nothing.html", + "==" + ] + ], + {} + ] + ], "css/css-multicol/multicol-gap-large-001.xht": [ [ "/css/css-multicol/multicol-gap-large-001.xht", @@ -46757,6 +46769,198 @@ {} ] ], + "css/css-style-attr/style-attr-braces-001.xht": [ + [ + "/css/css-style-attr/style-attr-braces-001.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-braces-002-quirks.htm": [ + [ + "/css/css-style-attr/style-attr-braces-002-quirks.htm", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-braces-002.xht": [ + [ + "/css/css-style-attr/style-attr-braces-002.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-braces-003.xht": [ + [ + "/css/css-style-attr/style-attr-braces-003.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-001.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-001.xht", + [ + [ + "/css/css-style-attr/reference/ref-green.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-002.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-002.xht", + [ + [ + "/css/css-style-attr/reference/ref-green.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-003.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-003.xht", + [ + [ + "/css/css-style-attr/reference/ref-green.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-004.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-004.xht", + [ + [ + "/css/css-style-attr/reference/ref-white-on-green-background.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-005.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-005.xht", + [ + [ + "/css/css-style-attr/reference/ref-white-on-green-background.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-006.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-006.xht", + [ + [ + "/css/css-style-attr/reference/ref-green.html", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-cascade-007.xht": [ + [ + "/css/css-style-attr/style-attr-cascade-007.xht", + [ + [ + "/css/css-style-attr/reference/style-attr-cascade-007.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-specificity-001.xht": [ + [ + "/css/css-style-attr/style-attr-specificity-001.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-specificity-002.xht": [ + [ + "/css/css-style-attr/style-attr-specificity-002.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-urls-001.xht": [ + [ + "/css/css-style-attr/style-attr-urls-001.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-urls-002.xht": [ + [ + "/css/css-style-attr/style-attr-urls-002.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green.xht", + "==" + ] + ], + {} + ] + ], + "css/css-style-attr/style-attr-urls-003.xht": [ + [ + "/css/css-style-attr/style-attr-urls-003.xht", + [ + [ + "/css/css-style-attr/reference/ref-green-on-green2.xht", + "==" + ] + ], + {} + ] + ], "css/css-tables/floats/floats-wrap-bfc-006b.xht": [ [ "/css/css-tables/floats/floats-wrap-bfc-006b.xht", @@ -109452,11 +109656,6 @@ {} ] ], - "css/css-multicol/multicol-fill-auto-ref.xht": [ - [ - {} - ] - ], "css/css-multicol/multicol-fill-balance-001-ref.xht": [ [ {} @@ -111022,6 +111221,231 @@ {} ] ], + "css/css-style-attr/reference/ref-green-on-green.xht": [ + [ + {} + ] + ], + "css/css-style-attr/reference/ref-green-on-green2.xht": [ + [ + {} + ] + ], + "css/css-style-attr/reference/ref-green.html": [ + [ + {} + ] + ], + "css/css-style-attr/reference/ref-white-on-green-background.html": [ + [ + {} + ] + ], + "css/css-style-attr/reference/style-attr-cascade-007.xht": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-green.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-lime.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-maroon.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-navy.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-red.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/1x1-white.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/60x60-gg-rr.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/60x60-green.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/60x60-red.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/a-green.css": [ + [ + {} + ] + ], + "css/css-style-attr/support/b-green.css": [ + [ + {} + ] + ], + "css/css-style-attr/support/c-red.css": [ + [ + {} + ] + ], + "css/css-style-attr/support/cat.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/pattern-grg-rgr-grg.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/pattern-grg-rrg-rgg.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/pattern-rgr-grg-rgr.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/pattern-tr.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/ruler-h-50%.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/ruler-h-50px.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/ruler-v-100px.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/ruler-v-50px.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/square-purple.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/square-teal.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/square-white.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/support/README": [ + [ + {} + ] + ], + "css/css-style-attr/support/support/swatch-green.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/support/swatch-red.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-blue.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-green.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-lime.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-orange.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-red.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-white.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/swatch-yellow.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-bl.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-br.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-inner-half-size.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-outer.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-tl.png": [ + [ + {} + ] + ], + "css/css-style-attr/support/test-tr.png": [ + [ + {} + ] + ], "css/css-syntax/OWNERS": [ [ {} @@ -120582,6 +121006,11 @@ {} ] ], + "css/reference/nothing.html": [ + [ + {} + ] + ], "css/reference/only_pass_parens_semicolon.html": [ [ {} @@ -140572,6 +141001,16 @@ {} ] ], + "mimesniff/mime-types/parsing.any-expected.txt": [ + [ + {} + ] + ], + "mimesniff/mime-types/parsing.any.worker-expected.txt": [ + [ + {} + ] + ], "mimesniff/mime-types/resources/generated-mime-types.json": [ [ {} @@ -188836,6 +189275,20 @@ {} ] ], + "mimesniff/mime-types/parsing.any.js": [ + [ + "/mimesniff/mime-types/parsing.any.html", + { + "timeout": "long" + } + ], + [ + "/mimesniff/mime-types/parsing.any.worker.html", + { + "timeout": "long" + } + ] + ], "mixed-content/audio-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html": [ [ "/mixed-content/audio-tag/http-csp/cross-origin-http/top-level/keep-scheme-redirect/optionally-blockable/opt-in-blocks.https.html", @@ -266271,10 +266724,6 @@ "f63446929f6a4a1f7ba2dba47af786c487fa03d7", "support" ], - "css/css-multicol/multicol-fill-auto-ref.xht": [ - "d97337c9c5fe4ff3ab4472b1c0f9f459f9d7cf8e", - "support" - ], "css/css-multicol/multicol-fill-balance-001-ref.xht": [ "dfdc227760f0fb524232d65ee792f108d32fc7de", "support" @@ -266319,6 +266768,10 @@ "9d12dc2b311ab4bf2dfda4565fcdfab0008754c5", "reftest" ], + "css/css-multicol/multicol-gap-fraction-002.html": [ + "67b2d75607ac68ad08012ad282ac4234946a1051", + "reftest" + ], "css/css-multicol/multicol-gap-large-001-ref.xht": [ "a502a720a1ac5a28f3857caf36ccb2a9fec02776", "support" @@ -269347,6 +269800,250 @@ "5bb192165bcb7d9a619d86dbff61831fc8de71cb", "support" ], + "css/css-style-attr/reference/ref-green-on-green.xht": [ + "3db4dec22e96cce52c575f4adb7a05f79917d4ea", + "support" + ], + "css/css-style-attr/reference/ref-green-on-green2.xht": [ + "9a4067fbea6534ad20a0354457eb7ade8053bbf6", + "support" + ], + "css/css-style-attr/reference/ref-green.html": [ + "8bc36f756c7ae32af5c52021c92bb04d1a0de876", + "support" + ], + "css/css-style-attr/reference/ref-white-on-green-background.html": [ + "ae526af2bb69429c5c8e7036dcfd79c6cc00f7ee", + "support" + ], + "css/css-style-attr/reference/style-attr-cascade-007.xht": [ + "1f4454897158d0a677832ac8e8e6e2d9190c10df", + "support" + ], + "css/css-style-attr/style-attr-braces-001.xht": [ + "fc9473d5492cc58e5ebaf44ae3981a05bae132aa", + "reftest" + ], + "css/css-style-attr/style-attr-braces-002-quirks.htm": [ + "134c9965cb75e87bb97a52040088755dbaf4eaa0", + "reftest" + ], + "css/css-style-attr/style-attr-braces-002.xht": [ + "c393e217b8e0f5b2bf329931440369caa7de959b", + "reftest" + ], + "css/css-style-attr/style-attr-braces-003.xht": [ + "d15816a22022609d0a127fc49fda4b0c56a2b4ee", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-001.xht": [ + "4d594acf436612e9ee6a378dbdf10671e286099c", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-002.xht": [ + "470926a6b6e174c1d217f2000001debe2d41913f", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-003.xht": [ + "ac31e81175c9571d7932ce227b54cbdf03c0dca9", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-004.xht": [ + "5cc034e3c039eaffb2042848ec3658c8af8f4c61", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-005.xht": [ + "1ae6ff87e9d7ebf270db8afbcf5c1b87468d9c7d", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-006.xht": [ + "dce3b7864fbaab8923134214316ad572a07e629f", + "reftest" + ], + "css/css-style-attr/style-attr-cascade-007.xht": [ + "7d317232b9ff6927e9bdb2c109440766dd766641", + "reftest" + ], + "css/css-style-attr/style-attr-specificity-001.xht": [ + "d9a5a0cd09a11cdf3dd328635b3297343e1bab5f", + "reftest" + ], + "css/css-style-attr/style-attr-specificity-002.xht": [ + "e4ffe1819f2278b4b0174e407eafc9d3599d0d34", + "reftest" + ], + "css/css-style-attr/style-attr-urls-001.xht": [ + "8669763b2dfa908532723b6c6673cc9641d88a8d", + "reftest" + ], + "css/css-style-attr/style-attr-urls-002.xht": [ + "3c30040c9a89a256fece892ce8b4611adbf48304", + "reftest" + ], + "css/css-style-attr/style-attr-urls-003.xht": [ + "3131ef4985d72c3a70461d451ff0f6b2a253895f", + "reftest" + ], + "css/css-style-attr/support/1x1-green.png": [ + "51e7b6974a09eda6cb31337717c5eaeb9c44b443", + "support" + ], + "css/css-style-attr/support/1x1-lime.png": [ + "b040eb633a35c0648ad72a2902361faf25bc419d", + "support" + ], + "css/css-style-attr/support/1x1-maroon.png": [ + "f78757e5ebe897bd618d100718385c84e00f2369", + "support" + ], + "css/css-style-attr/support/1x1-navy.png": [ + "a3fd80b2c79866fd343e18eef5a51ed6e835e53e", + "support" + ], + "css/css-style-attr/support/1x1-red.png": [ + "b8da86921d04ba42f42b0a60b03c5c2172f58c2b", + "support" + ], + "css/css-style-attr/support/1x1-white.png": [ + "71b246439f915ad21c7d39414d9f85c8ed73b4ca", + "support" + ], + "css/css-style-attr/support/60x60-gg-rr.png": [ + "e4843d42a26189132e1bdd53e8618521330baeca", + "support" + ], + "css/css-style-attr/support/60x60-green.png": [ + "2f8eb2409b0a18e0bff90725ec7eedc16e7be448", + "support" + ], + "css/css-style-attr/support/60x60-red.png": [ + "415b835abaaab822aab11880354296e7356bbb0a", + "support" + ], + "css/css-style-attr/support/a-green.css": [ + "a9716c222274ba868bfd06c05e28cb7762d93245", + "support" + ], + "css/css-style-attr/support/b-green.css": [ + "eb78a4d12f35b4249051826ea000c53d04df80b7", + "support" + ], + "css/css-style-attr/support/c-red.css": [ + "dc288b7aa49b57e0abf803741e78582ba5ceffdb", + "support" + ], + "css/css-style-attr/support/cat.png": [ + "461fd17b274662b88500cdf42bab7f3b79e6019d", + "support" + ], + "css/css-style-attr/support/pattern-grg-rgr-grg.png": [ + "cfb6ecc271c296c69b133a81f350a777b608bea4", + "support" + ], + "css/css-style-attr/support/pattern-grg-rrg-rgg.png": [ + "27080d4df556f59d4b501e03f2847bd9da5756a9", + "support" + ], + "css/css-style-attr/support/pattern-rgr-grg-rgr.png": [ + "c100a35c361205932c506f1b3399753b91e4c45e", + "support" + ], + "css/css-style-attr/support/pattern-tr.png": [ + "c1e687deee7b79ae091f2b42c4f6cff430076444", + "support" + ], + "css/css-style-attr/support/ruler-h-50%.png": [ + "9364be82a07500d6684a275174bcf5185444cb52", + "support" + ], + "css/css-style-attr/support/ruler-h-50px.png": [ + "b3d7cc680b20a5fc44ea93f7df6d33894bc7b09b", + "support" + ], + "css/css-style-attr/support/ruler-v-100px.png": [ + "d8b49696edb2bd614e9c00f96e7862798b6e621f", + "support" + ], + "css/css-style-attr/support/ruler-v-50px.png": [ + "eb299dc261ec04c8f2c11afb6f7a1c2ec147587b", + "support" + ], + "css/css-style-attr/support/square-purple.png": [ + "ef0619128f22e05920930420b7d96f91f860d904", + "support" + ], + "css/css-style-attr/support/square-teal.png": [ + "92efae44b710cf1ddd9ba96e593dae03fb2519c4", + "support" + ], + "css/css-style-attr/support/square-white.png": [ + "2f93fcc1462ba32b9b7899e5e78c869e529e68ee", + "support" + ], + "css/css-style-attr/support/support/README": [ + "18698bf71d328054eba0b473486058bc9286c1a4", + "support" + ], + "css/css-style-attr/support/support/swatch-green.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "css/css-style-attr/support/support/swatch-red.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "css/css-style-attr/support/swatch-blue.png": [ + "e79958e10feeeed3db88dee9bae9ea80055593c5", + "support" + ], + "css/css-style-attr/support/swatch-green.png": [ + "c51a03a807743f59e3027371ccfbd8e80235a485", + "support" + ], + "css/css-style-attr/support/swatch-lime.png": [ + "ee2cc3dcd6d8dda7c0e4ef3bbc7e63c74118211d", + "support" + ], + "css/css-style-attr/support/swatch-orange.png": [ + "10768a5177b772013e628c7397ae64725057295d", + "support" + ], + "css/css-style-attr/support/swatch-red.png": [ + "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d", + "support" + ], + "css/css-style-attr/support/swatch-white.png": [ + "5bccb1922de065e551d7d106e6493bb91040f3da", + "support" + ], + "css/css-style-attr/support/swatch-yellow.png": [ + "9cc73897c2e1fc45f5224d81d02a6b87bf72b1fa", + "support" + ], + "css/css-style-attr/support/test-bl.png": [ + "16e4eaa4864c10e72433e575f59c9b67763fe06a", + "support" + ], + "css/css-style-attr/support/test-br.png": [ + "37f65e7a21d9b9b2daa508f193b8f665c58a1ce9", + "support" + ], + "css/css-style-attr/support/test-inner-half-size.png": [ + "4ed63dd2bb54a8efc166719e00e1e27406b0ee59", + "support" + ], + "css/css-style-attr/support/test-outer.png": [ + "a0b8dfa40065b27f1d939ce0aab39ada3933c574", + "support" + ], + "css/css-style-attr/support/test-tl.png": [ + "956e5156fd8c0e75b1c0f3b8b3b900b653663f74", + "support" + ], + "css/css-style-attr/support/test-tr.png": [ + "078e1dd6dd61d36cec239ed75d02051f61fe60a5", + "support" + ], "css/css-syntax/OWNERS": [ "495f99b874611fd8f82f2e33bc4b7d930cc60fde", "support" @@ -290303,6 +291000,10 @@ "4aced258fbe6ada965f2a0707fad78878af7f162", "support" ], + "css/reference/nothing.html": [ + "c761e386839fbcc7eb1fc9c66f8839b3cd15ec95", + "support" + ], "css/reference/only_pass_parens_semicolon.html": [ "eec4a0a2b3f8f77c8b7c124e33617ce42c6e5209", "support" @@ -321079,6 +321780,18 @@ "baa985ca1fd0aed6644d9d1cef21764cfe826a8b", "testharness" ], + "mimesniff/mime-types/parsing.any-expected.txt": [ + "102170f15a37599e9e4346371fe6c6a6626540ea", + "support" + ], + "mimesniff/mime-types/parsing.any.js": [ + "b40a3e56406cd6f3303877b1da07a74d0d2f9deb", + "testharness" + ], + "mimesniff/mime-types/parsing.any.worker-expected.txt": [ + "102170f15a37599e9e4346371fe6c6a6626540ea", + "support" + ], "mimesniff/mime-types/resources/generated-mime-types.json": [ "e4610646e4a1a417e9fccf868150aed3c5688942", "support"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-auto-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-auto-ref.xht deleted file mode 100644 index b287fb2..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-auto-ref.xht +++ /dev/null
@@ -1,53 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>multicolumn | column-gap</title> -<link rel="author" title="Opera Software ASA" href="http://www.opera.com/"/> -<style type="text/css"><![CDATA[ -body>div { - font-family: ahem; - font-size: 0.5em; - line-height: 1em; - color: black; - height: 12em; - width: 100em; - -} -div div { - float: left; - width: 26em; - margin-right: 5em; -} -]]></style> -</head> - -<body> - -<div> - <div>one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred thousand million billion - trillion - one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred</div> - <div>thousand million billion - trillion - one two three four - five six seven eight - nine ten eleven twelve - thirtn fourtn fiftn sixtn - seventn eightn ninetn twenty - hundred thousand million billion - trillion</div> -</div> - -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any-expected.txt new file mode 100644 index 0000000..77f8830 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any-expected.txt
@@ -0,0 +1,1871 @@ +This is a testharness.js-based test. +Found 1857 tests; 697 PASS, 1160 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Loading data… +PASS text/html;charset=gbk (Blob/File) +PASS text/html;charset=gbk (Request/Response) +FAIL TEXT/HTML;CHARSET=GBK (Blob/File) assert_equals: Blob expected "text/html;charset=GBK" but got "text/html;charset=gbk" +FAIL TEXT/HTML;CHARSET=GBK (Request/Response) assert_equals: expected "text/html;charset=GBK" but got "text/html;charset=gbk" +FAIL text/html;charset=gbk( (Blob/File) assert_equals: Blob expected "text/html;charset=\"gbk(\"" but got "text/html;charset=gbk(" +FAIL text/html;charset=gbk( (Request/Response) assert_equals: expected "text/html;charset=\"gbk(\"" but got "text/html;charset=gbk(" +FAIL text/html;x=(;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;x=\"(\";charset=gbk" but got "text/html;x=(;charset=gbk" +FAIL text/html;x=(;charset=gbk (Request/Response) assert_equals: expected "text/html;x=\"(\";charset=gbk" but got "text/html;x=(;charset=gbk" +FAIL text/html;charset=gbk;charset=windows-1255 (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=gbk;charset=windows-1255" +FAIL text/html;charset=gbk;charset=windows-1255 (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=gbk;charset=windows-1255" +FAIL text/html;charset =gbk (Blob/File) assert_equals: Blob expected "text/html" but got "text/html;charset =gbk" +FAIL text/html;charset =gbk (Request/Response) assert_equals: expected "text/html" but got "text/html;charset =gbk" +FAIL text/html ;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html ;charset=gbk" +FAIL text/html ;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html ;charset=gbk" +FAIL text/html; charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html; charset=gbk" +FAIL text/html; charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html; charset=gbk" +FAIL text/html;charset= gbk (Blob/File) assert_equals: Blob expected "text/html;charset=\" gbk\"" but got "text/html;charset= gbk" +FAIL text/html;charset= gbk (Request/Response) assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html;charset= gbk" +PASS text/html;charset='gbk' (Blob/File) +PASS text/html;charset='gbk' (Request/Response) +PASS text/html;charset='gbk (Blob/File) +PASS text/html;charset='gbk (Request/Response) +PASS text/html;charset=gbk' (Blob/File) +PASS text/html;charset=gbk' (Request/Response) +FAIL text/html;test;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;test;charset=gbk" +FAIL text/html;test;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;test;charset=gbk" +FAIL text/html;test=;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;test=;charset=gbk" +FAIL text/html;test=;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;test=;charset=gbk" +FAIL text/html;';charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;';charset=gbk" +FAIL text/html;';charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;';charset=gbk" +FAIL text/html;";charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;\";charset=gbk" +FAIL text/html;";charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;\";charset=gbk" +FAIL text/html ; ; charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html ; ; charset=gbk" +FAIL text/html ; ; charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html ; ; charset=gbk" +FAIL text/html;;;;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;;;;charset=gbk" +FAIL text/html;;;;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;;;;charset=gbk" +FAIL text/html;charset="gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"" +FAIL text/html;charset="gbk" (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"" +FAIL text/html;charset="gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk" +FAIL text/html;charset="gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk" +FAIL text/html;charset=gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=\"gbk\\\"\"" but got "text/html;charset=gbk\"" +FAIL text/html;charset=gbk" (Request/Response) assert_equals: expected "text/html;charset=\"gbk\\\"\"" but got "text/html;charset=gbk\"" +PASS text/html;charset=" gbk" (Blob/File) +PASS text/html;charset=" gbk" (Request/Response) +FAIL text/html;charset="\ gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=\" gbk\"" but got "text/html;charset=\"\\ gbk\"" +FAIL text/html;charset="\ gbk" (Request/Response) assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html;charset=\"\\ gbk\"" +FAIL text/html;charset="\g\b\k" (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"\\g\b\k\"" +FAIL text/html;charset="\g\b\k" (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"\\g\b\k\"" +FAIL text/html;charset="gbk"x (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"x" +FAIL text/html;charset="gbk"x (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"x" +FAIL text/html;charset={gbk} (Blob/File) assert_equals: Blob expected "text/html;charset=\"{gbk}\"" but got "text/html;charset={gbk}" +FAIL text/html;charset={gbk} (Request/Response) assert_equals: expected "text/html;charset=\"{gbk}\"" but got "text/html;charset={gbk}" +PASS text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk (Blob/File) +PASS text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk (Request/Response) +PASS 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (Blob/File) +PASS 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (Request/Response) +FAIL !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz (Blob/File) assert_equals: Blob expected "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" but got "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +FAIL !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz (Request/Response) assert_equals: expected "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" but got "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +FAIL x/x;x=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" (Blob/File) assert_equals: Blob expected "x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"" but got "" +FAIL x/x;x=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" (Request/Response) assert_equals: expected "x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"" but got "" +FAIL x/x;test (Blob/File) assert_equals: Blob expected "x/x" but got "x/x;test" +FAIL x/x;test (Request/Response) assert_equals: expected "x/x" but got "x/x;test" +FAIL x/x;test="\ (Blob/File) assert_equals: Blob expected "x/x;test=\"\\\\"" but got "x/x;test=\"\\" +FAIL x/x;test="\ (Request/Response) assert_equals: expected "x/x;test=\"\\\\"" but got "x/x;test=\"\\" +FAIL x/x;x= (Blob/File) assert_equals: Blob expected "x/x" but got "x/x;x= " +FAIL x/x;x= (Request/Response) assert_equals: expected "x/x" but got "x/x;x=" +FAIL x/x;x= (Blob/File) assert_equals: Blob expected "x/x" but got "" +FAIL x/x;x= (Request/Response) assert_equals: expected "x/x" but got "x/x;x=" +FAIL text/html;test=ÿ;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;test=\"ÿ\";charset=gbk" but got "" +FAIL text/html;test=ÿ;charset=gbk (Request/Response) assert_equals: expected "text/html;test=\"ÿ\";charset=gbk" but got "" +FAIL x/x;test=�;x=x (Blob/File) assert_equals: Blob expected "x/x;x=x" but got "" +PASS x/x;test=�;x=x (Request/Response) +PASS (Blob/File) +PASS (Request/Response) +PASS (Blob/File) +PASS (Request/Response) +FAIL bogus (Blob/File) assert_equals: Blob expected "" but got "bogus" +FAIL bogus (Request/Response) assert_equals: expected "" but got "bogus" +FAIL bogus/ (Blob/File) assert_equals: Blob expected "" but got "bogus/" +FAIL bogus/ (Request/Response) assert_equals: expected "" but got "bogus/" +FAIL bogus/ (Blob/File) assert_equals: Blob expected "" but got "bogus/ " +FAIL bogus/ (Request/Response) assert_equals: expected "" but got "bogus/" +FAIL bogus/bogus/; (Blob/File) assert_equals: Blob expected "" but got "bogus/bogus/;" +FAIL bogus/bogus/; (Request/Response) assert_equals: expected "" but got "bogus/bogus/;" +FAIL </> (Blob/File) assert_equals: Blob expected "" but got "</>" +FAIL </> (Request/Response) assert_equals: expected "" but got "</>" +FAIL (/) (Blob/File) assert_equals: Blob expected "" but got "(/)" +FAIL (/) (Request/Response) assert_equals: expected "" but got "(/)" +FAIL text/html(;doesnot=matter (Blob/File) assert_equals: Blob expected "" but got "text/html(;doesnot=matter" +FAIL text/html(;doesnot=matter (Request/Response) assert_equals: expected "" but got "text/html(;doesnot=matter" +FAIL {/} (Blob/File) assert_equals: Blob expected "" but got "{/}" +FAIL {/} (Request/Response) assert_equals: expected "" but got "{/}" +PASS Ā/Ā (Blob/File) +PASS Ā/Ā (Request/Response) +PASS \0/x (Blob/File) +PASS \0/x (Request/Response) +PASS x/\0 (Blob/File) +PASS x/\0 (Request/Response) +FAIL x/x;\0=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;\0=x;bonus=x (Request/Response) +FAIL x/x;x=\0;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=\0;bonus=x (Request/Response) +FAIL x/x;x="\0";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x="\0";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +FAIL /x (Request/Response) assert_equals: expected "" but got "/x" +PASS x/ (Blob/File) +FAIL x/ (Request/Response) assert_equals: expected "" but got "x/" +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS +/x (Blob/File) +FAIL +/x (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +PASS x/ + (Blob/File) +FAIL x/ + (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +FAIL x/x; +=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x; +=x;bonus=x (Request/Response) +FAIL x/x;x= +;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x= +;bonus=x (Request/Response) +FAIL x/x;x=" +";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=" +";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS \r/x (Blob/File) +FAIL \r/x (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +PASS x/\r (Blob/File) +FAIL x/\r (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +FAIL x/x;\r=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;\r=x;bonus=x (Request/Response) +FAIL x/x;x=\r;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=\r;bonus=x (Request/Response) +FAIL x/x;x="\r";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x="\r";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL /x (Blob/File) assert_equals: Blob expected "" but got " /x" +FAIL /x (Request/Response) assert_equals: expected "" but got "/x" +FAIL x/ (Blob/File) assert_equals: Blob expected "" but got "x/ " +FAIL x/ (Request/Response) assert_equals: expected "" but got "x/" +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x; =x;bonus=x" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x; =x;bonus=x" +FAIL "/x (Blob/File) assert_equals: Blob expected "" but got "\"/x" +FAIL "/x (Request/Response) assert_equals: expected "" but got "\"/x" +FAIL x/" (Blob/File) assert_equals: Blob expected "" but got "x/\"" +FAIL x/" (Request/Response) assert_equals: expected "" but got "x/\"" +FAIL x/x;"=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;\"=x;bonus=x" +FAIL x/x;"=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;\"=x;bonus=x" +FAIL (/x (Blob/File) assert_equals: Blob expected "" but got "(/x" +FAIL (/x (Request/Response) assert_equals: expected "" but got "(/x" +FAIL x/( (Blob/File) assert_equals: Blob expected "" but got "x/(" +FAIL x/( (Request/Response) assert_equals: expected "" but got "x/(" +FAIL x/x;(=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;(=x;bonus=x" +FAIL x/x;(=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;(=x;bonus=x" +FAIL x/x;x=(;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"(\";bonus=x" but got "x/x;x=(;bonus=x" +FAIL x/x;x=(;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"(\";bonus=x" but got "x/x;x=(;bonus=x" +PASS x/x;x="(";bonus=x (Blob/File) +PASS x/x;x="(";bonus=x (Request/Response) +FAIL )/x (Blob/File) assert_equals: Blob expected "" but got ")/x" +FAIL )/x (Request/Response) assert_equals: expected "" but got ")/x" +FAIL x/) (Blob/File) assert_equals: Blob expected "" but got "x/)" +FAIL x/) (Request/Response) assert_equals: expected "" but got "x/)" +FAIL x/x;)=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;)=x;bonus=x" +FAIL x/x;)=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;)=x;bonus=x" +FAIL x/x;x=);bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\")\";bonus=x" but got "x/x;x=);bonus=x" +FAIL x/x;x=);bonus=x (Request/Response) assert_equals: expected "x/x;x=\")\";bonus=x" but got "x/x;x=);bonus=x" +PASS x/x;x=")";bonus=x (Blob/File) +PASS x/x;x=")";bonus=x (Request/Response) +FAIL ,/x (Blob/File) assert_equals: Blob expected "" but got ",/x" +FAIL ,/x (Request/Response) assert_equals: expected "" but got ",/x" +FAIL x/, (Blob/File) assert_equals: Blob expected "" but got "x/," +FAIL x/, (Request/Response) assert_equals: expected "" but got "x/," +FAIL x/x;,=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;,=x;bonus=x" +FAIL x/x;,=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;,=x;bonus=x" +FAIL x/x;x=,;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\",\";bonus=x" but got "x/x;x=,;bonus=x" +FAIL x/x;x=,;bonus=x (Request/Response) assert_equals: expected "x/x;x=\",\";bonus=x" but got "x/x;x=,;bonus=x" +PASS x/x;x=",";bonus=x (Blob/File) +PASS x/x;x=",";bonus=x (Request/Response) +FAIL x/x;/=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;/=x;bonus=x" +FAIL x/x;/=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;/=x;bonus=x" +FAIL x/x;x=/;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"/\";bonus=x" but got "x/x;x=/;bonus=x" +FAIL x/x;x=/;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"/\";bonus=x" but got "x/x;x=/;bonus=x" +PASS x/x;x="/";bonus=x (Blob/File) +PASS x/x;x="/";bonus=x (Request/Response) +FAIL :/x (Blob/File) assert_equals: Blob expected "" but got ":/x" +FAIL :/x (Request/Response) assert_equals: expected "" but got ":/x" +FAIL x/: (Blob/File) assert_equals: Blob expected "" but got "x/:" +FAIL x/: (Request/Response) assert_equals: expected "" but got "x/:" +FAIL x/x;:=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;:=x;bonus=x" +FAIL x/x;:=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;:=x;bonus=x" +FAIL x/x;x=:;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\":\";bonus=x" but got "x/x;x=:;bonus=x" +FAIL x/x;x=:;bonus=x (Request/Response) assert_equals: expected "x/x;x=\":\";bonus=x" but got "x/x;x=:;bonus=x" +PASS x/x;x=":";bonus=x (Blob/File) +PASS x/x;x=":";bonus=x (Request/Response) +FAIL ;/x (Blob/File) assert_equals: Blob expected "" but got ";/x" +FAIL ;/x (Request/Response) assert_equals: expected "" but got ";/x" +FAIL x/; (Blob/File) assert_equals: Blob expected "" but got "x/;" +FAIL x/; (Request/Response) assert_equals: expected "" but got "x/;" +FAIL </x (Blob/File) assert_equals: Blob expected "" but got "</x" +FAIL </x (Request/Response) assert_equals: expected "" but got "</x" +FAIL x/< (Blob/File) assert_equals: Blob expected "" but got "x/<" +FAIL x/< (Request/Response) assert_equals: expected "" but got "x/<" +FAIL x/x;<=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;<=x;bonus=x" +FAIL x/x;<=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;<=x;bonus=x" +FAIL x/x;x=<;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"<\";bonus=x" but got "x/x;x=<;bonus=x" +FAIL x/x;x=<;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"<\";bonus=x" but got "x/x;x=<;bonus=x" +PASS x/x;x="<";bonus=x (Blob/File) +PASS x/x;x="<";bonus=x (Request/Response) +FAIL =/x (Blob/File) assert_equals: Blob expected "" but got "=/x" +FAIL =/x (Request/Response) assert_equals: expected "" but got "=/x" +FAIL x/= (Blob/File) assert_equals: Blob expected "" but got "x/=" +FAIL x/= (Request/Response) assert_equals: expected "" but got "x/=" +FAIL x/x;x==;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"=\";bonus=x" but got "x/x;x==;bonus=x" +FAIL x/x;x==;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"=\";bonus=x" but got "x/x;x==;bonus=x" +PASS x/x;x="=";bonus=x (Blob/File) +PASS x/x;x="=";bonus=x (Request/Response) +FAIL >/x (Blob/File) assert_equals: Blob expected "" but got ">/x" +FAIL >/x (Request/Response) assert_equals: expected "" but got ">/x" +FAIL x/> (Blob/File) assert_equals: Blob expected "" but got "x/>" +FAIL x/> (Request/Response) assert_equals: expected "" but got "x/>" +FAIL x/x;>=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;>=x;bonus=x" +FAIL x/x;>=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;>=x;bonus=x" +FAIL x/x;x=>;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\">\";bonus=x" but got "x/x;x=>;bonus=x" +FAIL x/x;x=>;bonus=x (Request/Response) assert_equals: expected "x/x;x=\">\";bonus=x" but got "x/x;x=>;bonus=x" +PASS x/x;x=">";bonus=x (Blob/File) +PASS x/x;x=">";bonus=x (Request/Response) +FAIL ?/x (Blob/File) assert_equals: Blob expected "" but got "?/x" +FAIL ?/x (Request/Response) assert_equals: expected "" but got "?/x" +FAIL x/? (Blob/File) assert_equals: Blob expected "" but got "x/?" +FAIL x/? (Request/Response) assert_equals: expected "" but got "x/?" +FAIL x/x;?=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;?=x;bonus=x" +FAIL x/x;?=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;?=x;bonus=x" +FAIL x/x;x=?;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"?\";bonus=x" but got "x/x;x=?;bonus=x" +FAIL x/x;x=?;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"?\";bonus=x" but got "x/x;x=?;bonus=x" +PASS x/x;x="?";bonus=x (Blob/File) +PASS x/x;x="?";bonus=x (Request/Response) +FAIL @/x (Blob/File) assert_equals: Blob expected "" but got "@/x" +FAIL @/x (Request/Response) assert_equals: expected "" but got "@/x" +FAIL x/@ (Blob/File) assert_equals: Blob expected "" but got "x/@" +FAIL x/@ (Request/Response) assert_equals: expected "" but got "x/@" +FAIL x/x;@=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;@=x;bonus=x" +FAIL x/x;@=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;@=x;bonus=x" +FAIL x/x;x=@;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"@\";bonus=x" but got "x/x;x=@;bonus=x" +FAIL x/x;x=@;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"@\";bonus=x" but got "x/x;x=@;bonus=x" +PASS x/x;x="@";bonus=x (Blob/File) +PASS x/x;x="@";bonus=x (Request/Response) +FAIL [/x (Blob/File) assert_equals: Blob expected "" but got "[/x" +FAIL [/x (Request/Response) assert_equals: expected "" but got "[/x" +FAIL x/[ (Blob/File) assert_equals: Blob expected "" but got "x/[" +FAIL x/[ (Request/Response) assert_equals: expected "" but got "x/[" +FAIL x/x;[=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;[=x;bonus=x" +FAIL x/x;[=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;[=x;bonus=x" +FAIL x/x;x=[;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"[\";bonus=x" but got "x/x;x=[;bonus=x" +FAIL x/x;x=[;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"[\";bonus=x" but got "x/x;x=[;bonus=x" +PASS x/x;x="[";bonus=x (Blob/File) +PASS x/x;x="[";bonus=x (Request/Response) +FAIL \/x (Blob/File) assert_equals: Blob expected "" but got "\\/x" +FAIL \/x (Request/Response) assert_equals: expected "" but got "\\/x" +FAIL x/\ (Blob/File) assert_equals: Blob expected "" but got "x/\\" +FAIL x/\ (Request/Response) assert_equals: expected "" but got "x/\\" +FAIL x/x;\=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;\\=x;bonus=x" +FAIL x/x;\=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;\\=x;bonus=x" +FAIL ]/x (Blob/File) assert_equals: Blob expected "" but got "]/x" +FAIL ]/x (Request/Response) assert_equals: expected "" but got "]/x" +FAIL x/] (Blob/File) assert_equals: Blob expected "" but got "x/]" +FAIL x/] (Request/Response) assert_equals: expected "" but got "x/]" +FAIL x/x;]=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;]=x;bonus=x" +FAIL x/x;]=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;]=x;bonus=x" +FAIL x/x;x=];bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"]\";bonus=x" but got "x/x;x=];bonus=x" +FAIL x/x;x=];bonus=x (Request/Response) assert_equals: expected "x/x;x=\"]\";bonus=x" but got "x/x;x=];bonus=x" +PASS x/x;x="]";bonus=x (Blob/File) +PASS x/x;x="]";bonus=x (Request/Response) +FAIL {/x (Blob/File) assert_equals: Blob expected "" but got "{/x" +FAIL {/x (Request/Response) assert_equals: expected "" but got "{/x" +FAIL x/{ (Blob/File) assert_equals: Blob expected "" but got "x/{" +FAIL x/{ (Request/Response) assert_equals: expected "" but got "x/{" +FAIL x/x;{=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;{=x;bonus=x" +FAIL x/x;{=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;{=x;bonus=x" +FAIL x/x;x={;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"{\";bonus=x" but got "x/x;x={;bonus=x" +FAIL x/x;x={;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"{\";bonus=x" but got "x/x;x={;bonus=x" +PASS x/x;x="{";bonus=x (Blob/File) +PASS x/x;x="{";bonus=x (Request/Response) +FAIL }/x (Blob/File) assert_equals: Blob expected "" but got "}/x" +FAIL }/x (Request/Response) assert_equals: expected "" but got "}/x" +FAIL x/} (Blob/File) assert_equals: Blob expected "" but got "x/}" +FAIL x/} (Request/Response) assert_equals: expected "" but got "x/}" +FAIL x/x;}=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;}=x;bonus=x" +FAIL x/x;}=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;}=x;bonus=x" +FAIL x/x;x=};bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"}\";bonus=x" but got "x/x;x=};bonus=x" +FAIL x/x;x=};bonus=x (Request/Response) assert_equals: expected "x/x;x=\"}\";bonus=x" but got "x/x;x=};bonus=x" +PASS x/x;x="}";bonus=x (Blob/File) +PASS x/x;x="}";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +PASS ¡/x (Blob/File) +PASS ¡/x (Request/Response) +PASS x/¡ (Blob/File) +PASS x/¡ (Request/Response) +FAIL x/x;¡=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¡=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¡;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x=¡;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x="¡";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x="¡";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¡\";bonus=x" but got "" +PASS ¢/x (Blob/File) +PASS ¢/x (Request/Response) +PASS x/¢ (Blob/File) +PASS x/¢ (Request/Response) +FAIL x/x;¢=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¢=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¢;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x=¢;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x="¢";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x="¢";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¢\";bonus=x" but got "" +PASS £/x (Blob/File) +PASS £/x (Request/Response) +PASS x/£ (Blob/File) +PASS x/£ (Request/Response) +FAIL x/x;£=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;£=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=£;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x=£;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x="£";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x="£";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"£\";bonus=x" but got "" +PASS ¤/x (Blob/File) +PASS ¤/x (Request/Response) +PASS x/¤ (Blob/File) +PASS x/¤ (Request/Response) +FAIL x/x;¤=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¤=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¤;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x=¤;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x="¤";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x="¤";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¤\";bonus=x" but got "" +PASS ¥/x (Blob/File) +PASS ¥/x (Request/Response) +PASS x/¥ (Blob/File) +PASS x/¥ (Request/Response) +FAIL x/x;¥=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¥=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¥;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x=¥;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x="¥";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x="¥";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¥\";bonus=x" but got "" +PASS ¦/x (Blob/File) +PASS ¦/x (Request/Response) +PASS x/¦ (Blob/File) +PASS x/¦ (Request/Response) +FAIL x/x;¦=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¦=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¦;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x=¦;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x="¦";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x="¦";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¦\";bonus=x" but got "" +PASS §/x (Blob/File) +PASS §/x (Request/Response) +PASS x/§ (Blob/File) +PASS x/§ (Request/Response) +FAIL x/x;§=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;§=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=§;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x=§;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x="§";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x="§";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"§\";bonus=x" but got "" +PASS ¨/x (Blob/File) +PASS ¨/x (Request/Response) +PASS x/¨ (Blob/File) +PASS x/¨ (Request/Response) +FAIL x/x;¨=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¨=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¨;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x=¨;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x="¨";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x="¨";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¨\";bonus=x" but got "" +PASS ©/x (Blob/File) +PASS ©/x (Request/Response) +PASS x/© (Blob/File) +PASS x/© (Request/Response) +FAIL x/x;©=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;©=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=©;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x=©;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x="©";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x="©";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"©\";bonus=x" but got "" +PASS ª/x (Blob/File) +PASS ª/x (Request/Response) +PASS x/ª (Blob/File) +PASS x/ª (Request/Response) +FAIL x/x;ª=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ª=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ª;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x=ª;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x="ª";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x="ª";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ª\";bonus=x" but got "" +PASS «/x (Blob/File) +PASS «/x (Request/Response) +PASS x/« (Blob/File) +PASS x/« (Request/Response) +FAIL x/x;«=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;«=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=«;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x=«;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x="«";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x="«";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"«\";bonus=x" but got "" +PASS ¬/x (Blob/File) +PASS ¬/x (Request/Response) +PASS x/¬ (Blob/File) +PASS x/¬ (Request/Response) +FAIL x/x;¬=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¬=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¬;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x=¬;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x="¬";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x="¬";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¬\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS ®/x (Blob/File) +PASS ®/x (Request/Response) +PASS x/® (Blob/File) +PASS x/® (Request/Response) +FAIL x/x;®=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;®=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=®;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x=®;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x="®";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x="®";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"®\";bonus=x" but got "" +PASS ¯/x (Blob/File) +PASS ¯/x (Request/Response) +PASS x/¯ (Blob/File) +PASS x/¯ (Request/Response) +FAIL x/x;¯=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¯=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¯;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x=¯;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x="¯";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x="¯";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¯\";bonus=x" but got "" +PASS °/x (Blob/File) +PASS °/x (Request/Response) +PASS x/° (Blob/File) +PASS x/° (Request/Response) +FAIL x/x;°=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;°=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=°;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x=°;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x="°";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x="°";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"°\";bonus=x" but got "" +PASS ±/x (Blob/File) +PASS ±/x (Request/Response) +PASS x/± (Blob/File) +PASS x/± (Request/Response) +FAIL x/x;±=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;±=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=±;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x=±;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x="±";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x="±";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"±\";bonus=x" but got "" +PASS ²/x (Blob/File) +PASS ²/x (Request/Response) +PASS x/² (Blob/File) +PASS x/² (Request/Response) +FAIL x/x;²=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;²=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=²;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x=²;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x="²";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x="²";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"²\";bonus=x" but got "" +PASS ³/x (Blob/File) +PASS ³/x (Request/Response) +PASS x/³ (Blob/File) +PASS x/³ (Request/Response) +FAIL x/x;³=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;³=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=³;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x=³;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x="³";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x="³";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"³\";bonus=x" but got "" +PASS ´/x (Blob/File) +PASS ´/x (Request/Response) +PASS x/´ (Blob/File) +PASS x/´ (Request/Response) +FAIL x/x;´=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;´=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=´;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x=´;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x="´";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x="´";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"´\";bonus=x" but got "" +PASS µ/x (Blob/File) +PASS µ/x (Request/Response) +PASS x/µ (Blob/File) +PASS x/µ (Request/Response) +FAIL x/x;µ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;µ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=µ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x=µ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x="µ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x="µ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"µ\";bonus=x" but got "" +PASS ¶/x (Blob/File) +PASS ¶/x (Request/Response) +PASS x/¶ (Blob/File) +PASS x/¶ (Request/Response) +FAIL x/x;¶=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¶=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¶;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x=¶;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x="¶";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x="¶";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¶\";bonus=x" but got "" +PASS ·/x (Blob/File) +PASS ·/x (Request/Response) +PASS x/· (Blob/File) +PASS x/· (Request/Response) +FAIL x/x;·=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;·=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=·;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x=·;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x="·";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x="·";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"·\";bonus=x" but got "" +PASS ¸/x (Blob/File) +PASS ¸/x (Request/Response) +PASS x/¸ (Blob/File) +PASS x/¸ (Request/Response) +FAIL x/x;¸=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¸=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¸;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x=¸;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x="¸";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x="¸";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¸\";bonus=x" but got "" +PASS ¹/x (Blob/File) +PASS ¹/x (Request/Response) +PASS x/¹ (Blob/File) +PASS x/¹ (Request/Response) +FAIL x/x;¹=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¹=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¹;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x=¹;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x="¹";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x="¹";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¹\";bonus=x" but got "" +PASS º/x (Blob/File) +PASS º/x (Request/Response) +PASS x/º (Blob/File) +PASS x/º (Request/Response) +FAIL x/x;º=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;º=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=º;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x=º;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x="º";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x="º";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"º\";bonus=x" but got "" +PASS »/x (Blob/File) +PASS »/x (Request/Response) +PASS x/» (Blob/File) +PASS x/» (Request/Response) +FAIL x/x;»=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;»=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=»;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x=»;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x="»";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x="»";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"»\";bonus=x" but got "" +PASS ¼/x (Blob/File) +PASS ¼/x (Request/Response) +PASS x/¼ (Blob/File) +PASS x/¼ (Request/Response) +FAIL x/x;¼=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¼=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¼;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x=¼;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x="¼";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x="¼";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¼\";bonus=x" but got "" +PASS ½/x (Blob/File) +PASS ½/x (Request/Response) +PASS x/½ (Blob/File) +PASS x/½ (Request/Response) +FAIL x/x;½=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;½=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=½;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x=½;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x="½";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x="½";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"½\";bonus=x" but got "" +PASS ¾/x (Blob/File) +PASS ¾/x (Request/Response) +PASS x/¾ (Blob/File) +PASS x/¾ (Request/Response) +FAIL x/x;¾=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¾=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¾;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x=¾;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x="¾";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x="¾";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¾\";bonus=x" but got "" +PASS ¿/x (Blob/File) +PASS ¿/x (Request/Response) +PASS x/¿ (Blob/File) +PASS x/¿ (Request/Response) +FAIL x/x;¿=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¿=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¿;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x=¿;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x="¿";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x="¿";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¿\";bonus=x" but got "" +PASS À/x (Blob/File) +PASS À/x (Request/Response) +PASS x/À (Blob/File) +PASS x/À (Request/Response) +FAIL x/x;À=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;À=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=À;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x=À;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x="À";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x="À";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"À\";bonus=x" but got "" +PASS Á/x (Blob/File) +PASS Á/x (Request/Response) +PASS x/Á (Blob/File) +PASS x/Á (Request/Response) +FAIL x/x;Á=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Á=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Á;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x=Á;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x="Á";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x="Á";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Á\";bonus=x" but got "" +PASS Â/x (Blob/File) +PASS Â/x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;Â=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Â=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Â;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x=Â;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x="Â";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x="Â";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Â\";bonus=x" but got "" +PASS Ã/x (Blob/File) +PASS Ã/x (Request/Response) +PASS x/à (Blob/File) +PASS x/à (Request/Response) +FAIL x/x;Ã=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ã=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ã;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x=Ã;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x="Ã";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x="Ã";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ã\";bonus=x" but got "" +PASS Ä/x (Blob/File) +PASS Ä/x (Request/Response) +PASS x/Ä (Blob/File) +PASS x/Ä (Request/Response) +FAIL x/x;Ä=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ä=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ä;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x=Ä;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x="Ä";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x="Ä";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ä\";bonus=x" but got "" +PASS Å/x (Blob/File) +PASS Å/x (Request/Response) +PASS x/Å (Blob/File) +PASS x/Å (Request/Response) +FAIL x/x;Å=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Å=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Å;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x=Å;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x="Å";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x="Å";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Å\";bonus=x" but got "" +PASS Æ/x (Blob/File) +PASS Æ/x (Request/Response) +PASS x/Æ (Blob/File) +PASS x/Æ (Request/Response) +FAIL x/x;Æ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Æ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Æ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x=Æ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x="Æ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x="Æ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Æ\";bonus=x" but got "" +PASS Ç/x (Blob/File) +PASS Ç/x (Request/Response) +PASS x/Ç (Blob/File) +PASS x/Ç (Request/Response) +FAIL x/x;Ç=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ç=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ç;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x=Ç;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x="Ç";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x="Ç";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ç\";bonus=x" but got "" +PASS È/x (Blob/File) +PASS È/x (Request/Response) +PASS x/È (Blob/File) +PASS x/È (Request/Response) +FAIL x/x;È=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;È=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=È;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x=È;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x="È";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x="È";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"È\";bonus=x" but got "" +PASS É/x (Blob/File) +PASS É/x (Request/Response) +PASS x/É (Blob/File) +PASS x/É (Request/Response) +FAIL x/x;É=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;É=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=É;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x=É;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x="É";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x="É";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"É\";bonus=x" but got "" +PASS Ê/x (Blob/File) +PASS Ê/x (Request/Response) +PASS x/Ê (Blob/File) +PASS x/Ê (Request/Response) +FAIL x/x;Ê=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ê=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ê;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x=Ê;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x="Ê";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x="Ê";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ê\";bonus=x" but got "" +PASS Ë/x (Blob/File) +PASS Ë/x (Request/Response) +PASS x/Ë (Blob/File) +PASS x/Ë (Request/Response) +FAIL x/x;Ë=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ë=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ë;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x=Ë;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x="Ë";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x="Ë";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ë\";bonus=x" but got "" +PASS Ì/x (Blob/File) +PASS Ì/x (Request/Response) +PASS x/Ì (Blob/File) +PASS x/Ì (Request/Response) +FAIL x/x;Ì=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ì=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ì;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x=Ì;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x="Ì";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x="Ì";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ì\";bonus=x" but got "" +PASS Í/x (Blob/File) +PASS Í/x (Request/Response) +PASS x/Í (Blob/File) +PASS x/Í (Request/Response) +FAIL x/x;Í=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Í=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Í;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x=Í;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x="Í";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x="Í";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Í\";bonus=x" but got "" +PASS Î/x (Blob/File) +PASS Î/x (Request/Response) +PASS x/Î (Blob/File) +PASS x/Î (Request/Response) +FAIL x/x;Î=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Î=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Î;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x=Î;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x="Î";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x="Î";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Î\";bonus=x" but got "" +PASS Ï/x (Blob/File) +PASS Ï/x (Request/Response) +PASS x/Ï (Blob/File) +PASS x/Ï (Request/Response) +FAIL x/x;Ï=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ï=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ï;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x=Ï;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x="Ï";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x="Ï";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ï\";bonus=x" but got "" +PASS Ð/x (Blob/File) +PASS Ð/x (Request/Response) +PASS x/Ð (Blob/File) +PASS x/Ð (Request/Response) +FAIL x/x;Ð=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ð=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ð;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x=Ð;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x="Ð";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x="Ð";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ð\";bonus=x" but got "" +PASS Ñ/x (Blob/File) +PASS Ñ/x (Request/Response) +PASS x/Ñ (Blob/File) +PASS x/Ñ (Request/Response) +FAIL x/x;Ñ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ñ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ñ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x=Ñ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x="Ñ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x="Ñ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ñ\";bonus=x" but got "" +PASS Ò/x (Blob/File) +PASS Ò/x (Request/Response) +PASS x/Ò (Blob/File) +PASS x/Ò (Request/Response) +FAIL x/x;Ò=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ò=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ò;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x=Ò;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x="Ò";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x="Ò";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ò\";bonus=x" but got "" +PASS Ó/x (Blob/File) +PASS Ó/x (Request/Response) +PASS x/Ó (Blob/File) +PASS x/Ó (Request/Response) +FAIL x/x;Ó=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ó=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ó;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x=Ó;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x="Ó";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x="Ó";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ó\";bonus=x" but got "" +PASS Ô/x (Blob/File) +PASS Ô/x (Request/Response) +PASS x/Ô (Blob/File) +PASS x/Ô (Request/Response) +FAIL x/x;Ô=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ô=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ô;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x=Ô;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x="Ô";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x="Ô";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ô\";bonus=x" but got "" +PASS Õ/x (Blob/File) +PASS Õ/x (Request/Response) +PASS x/Õ (Blob/File) +PASS x/Õ (Request/Response) +FAIL x/x;Õ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Õ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Õ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x=Õ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x="Õ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x="Õ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Õ\";bonus=x" but got "" +PASS Ö/x (Blob/File) +PASS Ö/x (Request/Response) +PASS x/Ö (Blob/File) +PASS x/Ö (Request/Response) +FAIL x/x;Ö=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ö=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ö;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x=Ö;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x="Ö";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x="Ö";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ö\";bonus=x" but got "" +PASS ×/x (Blob/File) +PASS ×/x (Request/Response) +PASS x/× (Blob/File) +PASS x/× (Request/Response) +FAIL x/x;×=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;×=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=×;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x=×;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x="×";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x="×";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"×\";bonus=x" but got "" +PASS Ø/x (Blob/File) +PASS Ø/x (Request/Response) +PASS x/Ø (Blob/File) +PASS x/Ø (Request/Response) +FAIL x/x;Ø=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ø=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ø;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x=Ø;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x="Ø";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x="Ø";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ø\";bonus=x" but got "" +PASS Ù/x (Blob/File) +PASS Ù/x (Request/Response) +PASS x/Ù (Blob/File) +PASS x/Ù (Request/Response) +FAIL x/x;Ù=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ù=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ù;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x=Ù;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x="Ù";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x="Ù";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ù\";bonus=x" but got "" +PASS Ú/x (Blob/File) +PASS Ú/x (Request/Response) +PASS x/Ú (Blob/File) +PASS x/Ú (Request/Response) +FAIL x/x;Ú=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ú=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ú;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x=Ú;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x="Ú";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x="Ú";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ú\";bonus=x" but got "" +PASS Û/x (Blob/File) +PASS Û/x (Request/Response) +PASS x/Û (Blob/File) +PASS x/Û (Request/Response) +FAIL x/x;Û=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Û=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Û;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x=Û;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x="Û";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x="Û";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Û\";bonus=x" but got "" +PASS Ü/x (Blob/File) +PASS Ü/x (Request/Response) +PASS x/Ü (Blob/File) +PASS x/Ü (Request/Response) +FAIL x/x;Ü=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ü=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ü;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x=Ü;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x="Ü";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x="Ü";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ü\";bonus=x" but got "" +PASS Ý/x (Blob/File) +PASS Ý/x (Request/Response) +PASS x/Ý (Blob/File) +PASS x/Ý (Request/Response) +FAIL x/x;Ý=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ý=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ý;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x=Ý;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x="Ý";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x="Ý";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ý\";bonus=x" but got "" +PASS Þ/x (Blob/File) +PASS Þ/x (Request/Response) +PASS x/Þ (Blob/File) +PASS x/Þ (Request/Response) +FAIL x/x;Þ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Þ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Þ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x=Þ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x="Þ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x="Þ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Þ\";bonus=x" but got "" +PASS ß/x (Blob/File) +PASS ß/x (Request/Response) +PASS x/ß (Blob/File) +PASS x/ß (Request/Response) +FAIL x/x;ß=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ß=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ß;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x=ß;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x="ß";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x="ß";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ß\";bonus=x" but got "" +PASS à/x (Blob/File) +PASS à/x (Request/Response) +PASS x/à (Blob/File) +PASS x/à (Request/Response) +FAIL x/x;à=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;à=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=à;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x=à;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x="à";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x="à";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"à\";bonus=x" but got "" +PASS á/x (Blob/File) +PASS á/x (Request/Response) +PASS x/á (Blob/File) +PASS x/á (Request/Response) +FAIL x/x;á=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;á=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=á;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x=á;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x="á";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x="á";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"á\";bonus=x" but got "" +PASS â/x (Blob/File) +PASS â/x (Request/Response) +PASS x/â (Blob/File) +PASS x/â (Request/Response) +FAIL x/x;â=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;â=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=â;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x=â;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x="â";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x="â";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"â\";bonus=x" but got "" +PASS ã/x (Blob/File) +PASS ã/x (Request/Response) +PASS x/ã (Blob/File) +PASS x/ã (Request/Response) +FAIL x/x;ã=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ã=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ã;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x=ã;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x="ã";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x="ã";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ã\";bonus=x" but got "" +PASS ä/x (Blob/File) +PASS ä/x (Request/Response) +PASS x/ä (Blob/File) +PASS x/ä (Request/Response) +FAIL x/x;ä=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ä=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ä;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x=ä;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x="ä";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x="ä";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ä\";bonus=x" but got "" +PASS å/x (Blob/File) +PASS å/x (Request/Response) +PASS x/å (Blob/File) +PASS x/å (Request/Response) +FAIL x/x;å=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;å=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=å;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x=å;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x="å";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x="å";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"å\";bonus=x" but got "" +PASS æ/x (Blob/File) +PASS æ/x (Request/Response) +PASS x/æ (Blob/File) +PASS x/æ (Request/Response) +FAIL x/x;æ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;æ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=æ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x=æ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x="æ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x="æ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"æ\";bonus=x" but got "" +PASS ç/x (Blob/File) +PASS ç/x (Request/Response) +PASS x/ç (Blob/File) +PASS x/ç (Request/Response) +FAIL x/x;ç=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ç=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ç;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x=ç;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x="ç";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x="ç";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ç\";bonus=x" but got "" +PASS è/x (Blob/File) +PASS è/x (Request/Response) +PASS x/è (Blob/File) +PASS x/è (Request/Response) +FAIL x/x;è=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;è=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=è;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x=è;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x="è";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x="è";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"è\";bonus=x" but got "" +PASS é/x (Blob/File) +PASS é/x (Request/Response) +PASS x/é (Blob/File) +PASS x/é (Request/Response) +FAIL x/x;é=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;é=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=é;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x=é;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x="é";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x="é";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"é\";bonus=x" but got "" +PASS ê/x (Blob/File) +PASS ê/x (Request/Response) +PASS x/ê (Blob/File) +PASS x/ê (Request/Response) +FAIL x/x;ê=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ê=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ê;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x=ê;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x="ê";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x="ê";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ê\";bonus=x" but got "" +PASS ë/x (Blob/File) +PASS ë/x (Request/Response) +PASS x/ë (Blob/File) +PASS x/ë (Request/Response) +FAIL x/x;ë=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ë=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ë;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x=ë;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x="ë";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x="ë";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ë\";bonus=x" but got "" +PASS ì/x (Blob/File) +PASS ì/x (Request/Response) +PASS x/ì (Blob/File) +PASS x/ì (Request/Response) +FAIL x/x;ì=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ì=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ì;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x=ì;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x="ì";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x="ì";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ì\";bonus=x" but got "" +PASS í/x (Blob/File) +PASS í/x (Request/Response) +PASS x/í (Blob/File) +PASS x/í (Request/Response) +FAIL x/x;í=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;í=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=í;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x=í;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x="í";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x="í";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"í\";bonus=x" but got "" +PASS î/x (Blob/File) +PASS î/x (Request/Response) +PASS x/î (Blob/File) +PASS x/î (Request/Response) +FAIL x/x;î=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;î=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=î;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x=î;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x="î";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x="î";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"î\";bonus=x" but got "" +PASS ï/x (Blob/File) +PASS ï/x (Request/Response) +PASS x/ï (Blob/File) +PASS x/ï (Request/Response) +FAIL x/x;ï=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ï=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ï;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x=ï;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x="ï";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x="ï";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ï\";bonus=x" but got "" +PASS ð/x (Blob/File) +PASS ð/x (Request/Response) +PASS x/ð (Blob/File) +PASS x/ð (Request/Response) +FAIL x/x;ð=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ð=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ð;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x=ð;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x="ð";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x="ð";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ð\";bonus=x" but got "" +PASS ñ/x (Blob/File) +PASS ñ/x (Request/Response) +PASS x/ñ (Blob/File) +PASS x/ñ (Request/Response) +FAIL x/x;ñ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ñ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ñ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x=ñ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x="ñ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x="ñ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ñ\";bonus=x" but got "" +PASS ò/x (Blob/File) +PASS ò/x (Request/Response) +PASS x/ò (Blob/File) +PASS x/ò (Request/Response) +FAIL x/x;ò=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ò=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ò;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x=ò;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x="ò";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x="ò";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ò\";bonus=x" but got "" +PASS ó/x (Blob/File) +PASS ó/x (Request/Response) +PASS x/ó (Blob/File) +PASS x/ó (Request/Response) +FAIL x/x;ó=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ó=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ó;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x=ó;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x="ó";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x="ó";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ó\";bonus=x" but got "" +PASS ô/x (Blob/File) +PASS ô/x (Request/Response) +PASS x/ô (Blob/File) +PASS x/ô (Request/Response) +FAIL x/x;ô=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ô=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ô;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x=ô;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x="ô";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x="ô";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ô\";bonus=x" but got "" +PASS õ/x (Blob/File) +PASS õ/x (Request/Response) +PASS x/õ (Blob/File) +PASS x/õ (Request/Response) +FAIL x/x;õ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;õ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=õ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x=õ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x="õ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x="õ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"õ\";bonus=x" but got "" +PASS ö/x (Blob/File) +PASS ö/x (Request/Response) +PASS x/ö (Blob/File) +PASS x/ö (Request/Response) +FAIL x/x;ö=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ö=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ö;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x=ö;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x="ö";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x="ö";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ö\";bonus=x" but got "" +PASS ÷/x (Blob/File) +PASS ÷/x (Request/Response) +PASS x/÷ (Blob/File) +PASS x/÷ (Request/Response) +FAIL x/x;÷=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;÷=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=÷;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x=÷;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x="÷";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x="÷";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"÷\";bonus=x" but got "" +PASS ø/x (Blob/File) +PASS ø/x (Request/Response) +PASS x/ø (Blob/File) +PASS x/ø (Request/Response) +FAIL x/x;ø=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ø=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ø;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x=ø;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x="ø";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x="ø";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ø\";bonus=x" but got "" +PASS ù/x (Blob/File) +PASS ù/x (Request/Response) +PASS x/ù (Blob/File) +PASS x/ù (Request/Response) +FAIL x/x;ù=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ù=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ù;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x=ù;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x="ù";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x="ù";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ù\";bonus=x" but got "" +PASS ú/x (Blob/File) +PASS ú/x (Request/Response) +PASS x/ú (Blob/File) +PASS x/ú (Request/Response) +FAIL x/x;ú=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ú=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ú;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x=ú;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x="ú";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x="ú";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ú\";bonus=x" but got "" +PASS û/x (Blob/File) +PASS û/x (Request/Response) +PASS x/û (Blob/File) +PASS x/û (Request/Response) +FAIL x/x;û=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;û=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=û;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x=û;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x="û";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x="û";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"û\";bonus=x" but got "" +PASS ü/x (Blob/File) +PASS ü/x (Request/Response) +PASS x/ü (Blob/File) +PASS x/ü (Request/Response) +FAIL x/x;ü=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ü=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ü;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x=ü;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x="ü";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x="ü";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ü\";bonus=x" but got "" +PASS ý/x (Blob/File) +PASS ý/x (Request/Response) +PASS x/ý (Blob/File) +PASS x/ý (Request/Response) +FAIL x/x;ý=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ý=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ý;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x=ý;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x="ý";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x="ý";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ý\";bonus=x" but got "" +PASS þ/x (Blob/File) +PASS þ/x (Request/Response) +PASS x/þ (Blob/File) +PASS x/þ (Request/Response) +FAIL x/x;þ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;þ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=þ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x=þ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x="þ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x="þ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"þ\";bonus=x" but got "" +PASS ÿ/x (Blob/File) +PASS ÿ/x (Request/Response) +PASS x/ÿ (Blob/File) +PASS x/ÿ (Request/Response) +FAIL x/x;ÿ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ÿ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ÿ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x=ÿ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x="ÿ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x="ÿ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ÿ\";bonus=x" but got "" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.js b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.js new file mode 100644 index 0000000..bd9a62e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.js
@@ -0,0 +1,51 @@ +// META: timeout=long + +promise_test(() => { + return Promise.all([ + fetch("resources/mime-types.json"), + fetch("resources/generated-mime-types.json") + ]).then(([res, res2]) => res.json().then(runTests).then(() => res2.json().then(runTests))); +}, "Loading data…"); + +function isByteCompatible(str) { + for(let i = 0; i < str.length; i++) { + const charCode = str.charCodeAt(i); + // See https://github.com/w3c/web-platform-tests/issues/8372 for 0x0B and 0x0C + // See https://fetch.spec.whatwg.org/#concept-header-value for the remainder + if(charCode > 0xFF) { + return "incompatible"; + } else if(charCode === 0x00 || charCode === 0x0A || charCode === 0x0D) { + return "header-value-incompatible"; + } else if(charCode === 0x0B || charCode === 0x0C) { + return "wptserve-incompatible"; + } + } + return "compatible"; +} + +function runTests(tests) { + tests.forEach(val => { + if(typeof val === "string") { + return; + } + const output = val.output === null ? "" : val.output + test(() => { + assert_equals(new Blob([], { type: val.input}).type, output, "Blob"); + assert_equals(new File([], "noname", { type: val.input}).type, output, "File"); + }, val.input + " (Blob/File)"); + + promise_test(() => { + const compatibleNess = isByteCompatible(val.input); + if(compatibleNess === "incompatible" || compatibleNess === "header-value-incompatible") { + assert_throws(new TypeError(), () => new Request("about:blank", { headers: [["Content-Type", val.input]] })); + assert_throws(new TypeError(), () => new Response(null, { headers: [["Content-Type", val.input]] })); + return Promise.resolve(); + } else { + return Promise.all([ + new Request("about:blank", { headers: [["Content-Type", val.input]] }).blob().then(blob => assert_equals(blob.type, output)), + new Response(null, { headers: [["Content-Type", val.input]] }).blob().then(blob => assert_equals(blob.type, output)) + ]); + } + }, val.input + " (Request/Response)"); + }); +}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.worker-expected.txt new file mode 100644 index 0000000..77f8830 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/mimesniff/mime-types/parsing.any.worker-expected.txt
@@ -0,0 +1,1871 @@ +This is a testharness.js-based test. +Found 1857 tests; 697 PASS, 1160 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Loading data… +PASS text/html;charset=gbk (Blob/File) +PASS text/html;charset=gbk (Request/Response) +FAIL TEXT/HTML;CHARSET=GBK (Blob/File) assert_equals: Blob expected "text/html;charset=GBK" but got "text/html;charset=gbk" +FAIL TEXT/HTML;CHARSET=GBK (Request/Response) assert_equals: expected "text/html;charset=GBK" but got "text/html;charset=gbk" +FAIL text/html;charset=gbk( (Blob/File) assert_equals: Blob expected "text/html;charset=\"gbk(\"" but got "text/html;charset=gbk(" +FAIL text/html;charset=gbk( (Request/Response) assert_equals: expected "text/html;charset=\"gbk(\"" but got "text/html;charset=gbk(" +FAIL text/html;x=(;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;x=\"(\";charset=gbk" but got "text/html;x=(;charset=gbk" +FAIL text/html;x=(;charset=gbk (Request/Response) assert_equals: expected "text/html;x=\"(\";charset=gbk" but got "text/html;x=(;charset=gbk" +FAIL text/html;charset=gbk;charset=windows-1255 (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=gbk;charset=windows-1255" +FAIL text/html;charset=gbk;charset=windows-1255 (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=gbk;charset=windows-1255" +FAIL text/html;charset =gbk (Blob/File) assert_equals: Blob expected "text/html" but got "text/html;charset =gbk" +FAIL text/html;charset =gbk (Request/Response) assert_equals: expected "text/html" but got "text/html;charset =gbk" +FAIL text/html ;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html ;charset=gbk" +FAIL text/html ;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html ;charset=gbk" +FAIL text/html; charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html; charset=gbk" +FAIL text/html; charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html; charset=gbk" +FAIL text/html;charset= gbk (Blob/File) assert_equals: Blob expected "text/html;charset=\" gbk\"" but got "text/html;charset= gbk" +FAIL text/html;charset= gbk (Request/Response) assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html;charset= gbk" +PASS text/html;charset='gbk' (Blob/File) +PASS text/html;charset='gbk' (Request/Response) +PASS text/html;charset='gbk (Blob/File) +PASS text/html;charset='gbk (Request/Response) +PASS text/html;charset=gbk' (Blob/File) +PASS text/html;charset=gbk' (Request/Response) +FAIL text/html;test;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;test;charset=gbk" +FAIL text/html;test;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;test;charset=gbk" +FAIL text/html;test=;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;test=;charset=gbk" +FAIL text/html;test=;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;test=;charset=gbk" +FAIL text/html;';charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;';charset=gbk" +FAIL text/html;';charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;';charset=gbk" +FAIL text/html;";charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;\";charset=gbk" +FAIL text/html;";charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;\";charset=gbk" +FAIL text/html ; ; charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html ; ; charset=gbk" +FAIL text/html ; ; charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html ; ; charset=gbk" +FAIL text/html;;;;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;;;;charset=gbk" +FAIL text/html;;;;charset=gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;;;;charset=gbk" +FAIL text/html;charset="gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"" +FAIL text/html;charset="gbk" (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"" +FAIL text/html;charset="gbk (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk" +FAIL text/html;charset="gbk (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk" +FAIL text/html;charset=gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=\"gbk\\\"\"" but got "text/html;charset=gbk\"" +FAIL text/html;charset=gbk" (Request/Response) assert_equals: expected "text/html;charset=\"gbk\\\"\"" but got "text/html;charset=gbk\"" +PASS text/html;charset=" gbk" (Blob/File) +PASS text/html;charset=" gbk" (Request/Response) +FAIL text/html;charset="\ gbk" (Blob/File) assert_equals: Blob expected "text/html;charset=\" gbk\"" but got "text/html;charset=\"\\ gbk\"" +FAIL text/html;charset="\ gbk" (Request/Response) assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html;charset=\"\\ gbk\"" +FAIL text/html;charset="\g\b\k" (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"\\g\b\k\"" +FAIL text/html;charset="\g\b\k" (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"\\g\b\k\"" +FAIL text/html;charset="gbk"x (Blob/File) assert_equals: Blob expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"x" +FAIL text/html;charset="gbk"x (Request/Response) assert_equals: expected "text/html;charset=gbk" but got "text/html;charset=\"gbk\"x" +FAIL text/html;charset={gbk} (Blob/File) assert_equals: Blob expected "text/html;charset=\"{gbk}\"" but got "text/html;charset={gbk}" +FAIL text/html;charset={gbk} (Request/Response) assert_equals: expected "text/html;charset=\"{gbk}\"" but got "text/html;charset={gbk}" +PASS text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk (Blob/File) +PASS text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk (Request/Response) +PASS 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (Blob/File) +PASS 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (Request/Response) +FAIL !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz (Blob/File) assert_equals: Blob expected "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" but got "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +FAIL !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz (Request/Response) assert_equals: expected "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" but got "!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +FAIL x/x;x=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" (Blob/File) assert_equals: Blob expected "x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"" but got "" +FAIL x/x;x=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" (Request/Response) assert_equals: expected "x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"" but got "" +FAIL x/x;test (Blob/File) assert_equals: Blob expected "x/x" but got "x/x;test" +FAIL x/x;test (Request/Response) assert_equals: expected "x/x" but got "x/x;test" +FAIL x/x;test="\ (Blob/File) assert_equals: Blob expected "x/x;test=\"\\\\"" but got "x/x;test=\"\\" +FAIL x/x;test="\ (Request/Response) assert_equals: expected "x/x;test=\"\\\\"" but got "x/x;test=\"\\" +FAIL x/x;x= (Blob/File) assert_equals: Blob expected "x/x" but got "x/x;x= " +FAIL x/x;x= (Request/Response) assert_equals: expected "x/x" but got "x/x;x=" +FAIL x/x;x= (Blob/File) assert_equals: Blob expected "x/x" but got "" +FAIL x/x;x= (Request/Response) assert_equals: expected "x/x" but got "x/x;x=" +FAIL text/html;test=ÿ;charset=gbk (Blob/File) assert_equals: Blob expected "text/html;test=\"ÿ\";charset=gbk" but got "" +FAIL text/html;test=ÿ;charset=gbk (Request/Response) assert_equals: expected "text/html;test=\"ÿ\";charset=gbk" but got "" +FAIL x/x;test=�;x=x (Blob/File) assert_equals: Blob expected "x/x;x=x" but got "" +PASS x/x;test=�;x=x (Request/Response) +PASS (Blob/File) +PASS (Request/Response) +PASS (Blob/File) +PASS (Request/Response) +FAIL bogus (Blob/File) assert_equals: Blob expected "" but got "bogus" +FAIL bogus (Request/Response) assert_equals: expected "" but got "bogus" +FAIL bogus/ (Blob/File) assert_equals: Blob expected "" but got "bogus/" +FAIL bogus/ (Request/Response) assert_equals: expected "" but got "bogus/" +FAIL bogus/ (Blob/File) assert_equals: Blob expected "" but got "bogus/ " +FAIL bogus/ (Request/Response) assert_equals: expected "" but got "bogus/" +FAIL bogus/bogus/; (Blob/File) assert_equals: Blob expected "" but got "bogus/bogus/;" +FAIL bogus/bogus/; (Request/Response) assert_equals: expected "" but got "bogus/bogus/;" +FAIL </> (Blob/File) assert_equals: Blob expected "" but got "</>" +FAIL </> (Request/Response) assert_equals: expected "" but got "</>" +FAIL (/) (Blob/File) assert_equals: Blob expected "" but got "(/)" +FAIL (/) (Request/Response) assert_equals: expected "" but got "(/)" +FAIL text/html(;doesnot=matter (Blob/File) assert_equals: Blob expected "" but got "text/html(;doesnot=matter" +FAIL text/html(;doesnot=matter (Request/Response) assert_equals: expected "" but got "text/html(;doesnot=matter" +FAIL {/} (Blob/File) assert_equals: Blob expected "" but got "{/}" +FAIL {/} (Request/Response) assert_equals: expected "" but got "{/}" +PASS Ā/Ā (Blob/File) +PASS Ā/Ā (Request/Response) +PASS \0/x (Blob/File) +PASS \0/x (Request/Response) +PASS x/\0 (Blob/File) +PASS x/\0 (Request/Response) +FAIL x/x;\0=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;\0=x;bonus=x (Request/Response) +FAIL x/x;x=\0;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=\0;bonus=x (Request/Response) +FAIL x/x;x="\0";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x="\0";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +FAIL /x (Request/Response) assert_equals: expected "" but got "/x" +PASS x/ (Blob/File) +FAIL x/ (Request/Response) assert_equals: expected "" but got "x/" +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS +/x (Blob/File) +FAIL +/x (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +PASS x/ + (Blob/File) +FAIL x/ + (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +FAIL x/x; +=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x; +=x;bonus=x (Request/Response) +FAIL x/x;x= +;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x= +;bonus=x (Request/Response) +FAIL x/x;x=" +";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=" +";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS \r/x (Blob/File) +FAIL \r/x (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +PASS x/\r (Blob/File) +FAIL x/\r (Request/Response) assert_throws: function "() => new Request("about:blank", { headers: [["Content-Type", val.input]] })" did not throw +FAIL x/x;\r=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;\r=x;bonus=x (Request/Response) +FAIL x/x;x=\r;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x=\r;bonus=x (Request/Response) +FAIL x/x;x="\r";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +PASS x/x;x="\r";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL /x (Blob/File) assert_equals: Blob expected "" but got " /x" +FAIL /x (Request/Response) assert_equals: expected "" but got "/x" +FAIL x/ (Blob/File) assert_equals: Blob expected "" but got "x/ " +FAIL x/ (Request/Response) assert_equals: expected "" but got "x/" +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x; =x;bonus=x" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x; =x;bonus=x" +FAIL "/x (Blob/File) assert_equals: Blob expected "" but got "\"/x" +FAIL "/x (Request/Response) assert_equals: expected "" but got "\"/x" +FAIL x/" (Blob/File) assert_equals: Blob expected "" but got "x/\"" +FAIL x/" (Request/Response) assert_equals: expected "" but got "x/\"" +FAIL x/x;"=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;\"=x;bonus=x" +FAIL x/x;"=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;\"=x;bonus=x" +FAIL (/x (Blob/File) assert_equals: Blob expected "" but got "(/x" +FAIL (/x (Request/Response) assert_equals: expected "" but got "(/x" +FAIL x/( (Blob/File) assert_equals: Blob expected "" but got "x/(" +FAIL x/( (Request/Response) assert_equals: expected "" but got "x/(" +FAIL x/x;(=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;(=x;bonus=x" +FAIL x/x;(=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;(=x;bonus=x" +FAIL x/x;x=(;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"(\";bonus=x" but got "x/x;x=(;bonus=x" +FAIL x/x;x=(;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"(\";bonus=x" but got "x/x;x=(;bonus=x" +PASS x/x;x="(";bonus=x (Blob/File) +PASS x/x;x="(";bonus=x (Request/Response) +FAIL )/x (Blob/File) assert_equals: Blob expected "" but got ")/x" +FAIL )/x (Request/Response) assert_equals: expected "" but got ")/x" +FAIL x/) (Blob/File) assert_equals: Blob expected "" but got "x/)" +FAIL x/) (Request/Response) assert_equals: expected "" but got "x/)" +FAIL x/x;)=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;)=x;bonus=x" +FAIL x/x;)=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;)=x;bonus=x" +FAIL x/x;x=);bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\")\";bonus=x" but got "x/x;x=);bonus=x" +FAIL x/x;x=);bonus=x (Request/Response) assert_equals: expected "x/x;x=\")\";bonus=x" but got "x/x;x=);bonus=x" +PASS x/x;x=")";bonus=x (Blob/File) +PASS x/x;x=")";bonus=x (Request/Response) +FAIL ,/x (Blob/File) assert_equals: Blob expected "" but got ",/x" +FAIL ,/x (Request/Response) assert_equals: expected "" but got ",/x" +FAIL x/, (Blob/File) assert_equals: Blob expected "" but got "x/," +FAIL x/, (Request/Response) assert_equals: expected "" but got "x/," +FAIL x/x;,=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;,=x;bonus=x" +FAIL x/x;,=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;,=x;bonus=x" +FAIL x/x;x=,;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\",\";bonus=x" but got "x/x;x=,;bonus=x" +FAIL x/x;x=,;bonus=x (Request/Response) assert_equals: expected "x/x;x=\",\";bonus=x" but got "x/x;x=,;bonus=x" +PASS x/x;x=",";bonus=x (Blob/File) +PASS x/x;x=",";bonus=x (Request/Response) +FAIL x/x;/=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;/=x;bonus=x" +FAIL x/x;/=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;/=x;bonus=x" +FAIL x/x;x=/;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"/\";bonus=x" but got "x/x;x=/;bonus=x" +FAIL x/x;x=/;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"/\";bonus=x" but got "x/x;x=/;bonus=x" +PASS x/x;x="/";bonus=x (Blob/File) +PASS x/x;x="/";bonus=x (Request/Response) +FAIL :/x (Blob/File) assert_equals: Blob expected "" but got ":/x" +FAIL :/x (Request/Response) assert_equals: expected "" but got ":/x" +FAIL x/: (Blob/File) assert_equals: Blob expected "" but got "x/:" +FAIL x/: (Request/Response) assert_equals: expected "" but got "x/:" +FAIL x/x;:=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;:=x;bonus=x" +FAIL x/x;:=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;:=x;bonus=x" +FAIL x/x;x=:;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\":\";bonus=x" but got "x/x;x=:;bonus=x" +FAIL x/x;x=:;bonus=x (Request/Response) assert_equals: expected "x/x;x=\":\";bonus=x" but got "x/x;x=:;bonus=x" +PASS x/x;x=":";bonus=x (Blob/File) +PASS x/x;x=":";bonus=x (Request/Response) +FAIL ;/x (Blob/File) assert_equals: Blob expected "" but got ";/x" +FAIL ;/x (Request/Response) assert_equals: expected "" but got ";/x" +FAIL x/; (Blob/File) assert_equals: Blob expected "" but got "x/;" +FAIL x/; (Request/Response) assert_equals: expected "" but got "x/;" +FAIL </x (Blob/File) assert_equals: Blob expected "" but got "</x" +FAIL </x (Request/Response) assert_equals: expected "" but got "</x" +FAIL x/< (Blob/File) assert_equals: Blob expected "" but got "x/<" +FAIL x/< (Request/Response) assert_equals: expected "" but got "x/<" +FAIL x/x;<=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;<=x;bonus=x" +FAIL x/x;<=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;<=x;bonus=x" +FAIL x/x;x=<;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"<\";bonus=x" but got "x/x;x=<;bonus=x" +FAIL x/x;x=<;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"<\";bonus=x" but got "x/x;x=<;bonus=x" +PASS x/x;x="<";bonus=x (Blob/File) +PASS x/x;x="<";bonus=x (Request/Response) +FAIL =/x (Blob/File) assert_equals: Blob expected "" but got "=/x" +FAIL =/x (Request/Response) assert_equals: expected "" but got "=/x" +FAIL x/= (Blob/File) assert_equals: Blob expected "" but got "x/=" +FAIL x/= (Request/Response) assert_equals: expected "" but got "x/=" +FAIL x/x;x==;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"=\";bonus=x" but got "x/x;x==;bonus=x" +FAIL x/x;x==;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"=\";bonus=x" but got "x/x;x==;bonus=x" +PASS x/x;x="=";bonus=x (Blob/File) +PASS x/x;x="=";bonus=x (Request/Response) +FAIL >/x (Blob/File) assert_equals: Blob expected "" but got ">/x" +FAIL >/x (Request/Response) assert_equals: expected "" but got ">/x" +FAIL x/> (Blob/File) assert_equals: Blob expected "" but got "x/>" +FAIL x/> (Request/Response) assert_equals: expected "" but got "x/>" +FAIL x/x;>=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;>=x;bonus=x" +FAIL x/x;>=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;>=x;bonus=x" +FAIL x/x;x=>;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\">\";bonus=x" but got "x/x;x=>;bonus=x" +FAIL x/x;x=>;bonus=x (Request/Response) assert_equals: expected "x/x;x=\">\";bonus=x" but got "x/x;x=>;bonus=x" +PASS x/x;x=">";bonus=x (Blob/File) +PASS x/x;x=">";bonus=x (Request/Response) +FAIL ?/x (Blob/File) assert_equals: Blob expected "" but got "?/x" +FAIL ?/x (Request/Response) assert_equals: expected "" but got "?/x" +FAIL x/? (Blob/File) assert_equals: Blob expected "" but got "x/?" +FAIL x/? (Request/Response) assert_equals: expected "" but got "x/?" +FAIL x/x;?=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;?=x;bonus=x" +FAIL x/x;?=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;?=x;bonus=x" +FAIL x/x;x=?;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"?\";bonus=x" but got "x/x;x=?;bonus=x" +FAIL x/x;x=?;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"?\";bonus=x" but got "x/x;x=?;bonus=x" +PASS x/x;x="?";bonus=x (Blob/File) +PASS x/x;x="?";bonus=x (Request/Response) +FAIL @/x (Blob/File) assert_equals: Blob expected "" but got "@/x" +FAIL @/x (Request/Response) assert_equals: expected "" but got "@/x" +FAIL x/@ (Blob/File) assert_equals: Blob expected "" but got "x/@" +FAIL x/@ (Request/Response) assert_equals: expected "" but got "x/@" +FAIL x/x;@=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;@=x;bonus=x" +FAIL x/x;@=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;@=x;bonus=x" +FAIL x/x;x=@;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"@\";bonus=x" but got "x/x;x=@;bonus=x" +FAIL x/x;x=@;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"@\";bonus=x" but got "x/x;x=@;bonus=x" +PASS x/x;x="@";bonus=x (Blob/File) +PASS x/x;x="@";bonus=x (Request/Response) +FAIL [/x (Blob/File) assert_equals: Blob expected "" but got "[/x" +FAIL [/x (Request/Response) assert_equals: expected "" but got "[/x" +FAIL x/[ (Blob/File) assert_equals: Blob expected "" but got "x/[" +FAIL x/[ (Request/Response) assert_equals: expected "" but got "x/[" +FAIL x/x;[=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;[=x;bonus=x" +FAIL x/x;[=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;[=x;bonus=x" +FAIL x/x;x=[;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"[\";bonus=x" but got "x/x;x=[;bonus=x" +FAIL x/x;x=[;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"[\";bonus=x" but got "x/x;x=[;bonus=x" +PASS x/x;x="[";bonus=x (Blob/File) +PASS x/x;x="[";bonus=x (Request/Response) +FAIL \/x (Blob/File) assert_equals: Blob expected "" but got "\\/x" +FAIL \/x (Request/Response) assert_equals: expected "" but got "\\/x" +FAIL x/\ (Blob/File) assert_equals: Blob expected "" but got "x/\\" +FAIL x/\ (Request/Response) assert_equals: expected "" but got "x/\\" +FAIL x/x;\=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;\\=x;bonus=x" +FAIL x/x;\=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;\\=x;bonus=x" +FAIL ]/x (Blob/File) assert_equals: Blob expected "" but got "]/x" +FAIL ]/x (Request/Response) assert_equals: expected "" but got "]/x" +FAIL x/] (Blob/File) assert_equals: Blob expected "" but got "x/]" +FAIL x/] (Request/Response) assert_equals: expected "" but got "x/]" +FAIL x/x;]=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;]=x;bonus=x" +FAIL x/x;]=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;]=x;bonus=x" +FAIL x/x;x=];bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"]\";bonus=x" but got "x/x;x=];bonus=x" +FAIL x/x;x=];bonus=x (Request/Response) assert_equals: expected "x/x;x=\"]\";bonus=x" but got "x/x;x=];bonus=x" +PASS x/x;x="]";bonus=x (Blob/File) +PASS x/x;x="]";bonus=x (Request/Response) +FAIL {/x (Blob/File) assert_equals: Blob expected "" but got "{/x" +FAIL {/x (Request/Response) assert_equals: expected "" but got "{/x" +FAIL x/{ (Blob/File) assert_equals: Blob expected "" but got "x/{" +FAIL x/{ (Request/Response) assert_equals: expected "" but got "x/{" +FAIL x/x;{=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;{=x;bonus=x" +FAIL x/x;{=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;{=x;bonus=x" +FAIL x/x;x={;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"{\";bonus=x" but got "x/x;x={;bonus=x" +FAIL x/x;x={;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"{\";bonus=x" but got "x/x;x={;bonus=x" +PASS x/x;x="{";bonus=x (Blob/File) +PASS x/x;x="{";bonus=x (Request/Response) +FAIL }/x (Blob/File) assert_equals: Blob expected "" but got "}/x" +FAIL }/x (Request/Response) assert_equals: expected "" but got "}/x" +FAIL x/} (Blob/File) assert_equals: Blob expected "" but got "x/}" +FAIL x/} (Request/Response) assert_equals: expected "" but got "x/}" +FAIL x/x;}=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "x/x;}=x;bonus=x" +FAIL x/x;}=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "x/x;}=x;bonus=x" +FAIL x/x;x=};bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"}\";bonus=x" but got "x/x;x=};bonus=x" +FAIL x/x;x=};bonus=x (Request/Response) assert_equals: expected "x/x;x=\"}\";bonus=x" but got "x/x;x=};bonus=x" +PASS x/x;x="}";bonus=x (Blob/File) +PASS x/x;x="}";bonus=x (Request/Response) +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x; =x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x; =x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x= ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\" \";bonus=x" but got "" +FAIL x/x;x=" ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\" \";bonus=x" but got "" +PASS ¡/x (Blob/File) +PASS ¡/x (Request/Response) +PASS x/¡ (Blob/File) +PASS x/¡ (Request/Response) +FAIL x/x;¡=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¡=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¡;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x=¡;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x="¡";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¡\";bonus=x" but got "" +FAIL x/x;x="¡";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¡\";bonus=x" but got "" +PASS ¢/x (Blob/File) +PASS ¢/x (Request/Response) +PASS x/¢ (Blob/File) +PASS x/¢ (Request/Response) +FAIL x/x;¢=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¢=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¢;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x=¢;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x="¢";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¢\";bonus=x" but got "" +FAIL x/x;x="¢";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¢\";bonus=x" but got "" +PASS £/x (Blob/File) +PASS £/x (Request/Response) +PASS x/£ (Blob/File) +PASS x/£ (Request/Response) +FAIL x/x;£=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;£=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=£;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x=£;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x="£";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"£\";bonus=x" but got "" +FAIL x/x;x="£";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"£\";bonus=x" but got "" +PASS ¤/x (Blob/File) +PASS ¤/x (Request/Response) +PASS x/¤ (Blob/File) +PASS x/¤ (Request/Response) +FAIL x/x;¤=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¤=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¤;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x=¤;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x="¤";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¤\";bonus=x" but got "" +FAIL x/x;x="¤";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¤\";bonus=x" but got "" +PASS ¥/x (Blob/File) +PASS ¥/x (Request/Response) +PASS x/¥ (Blob/File) +PASS x/¥ (Request/Response) +FAIL x/x;¥=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¥=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¥;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x=¥;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x="¥";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¥\";bonus=x" but got "" +FAIL x/x;x="¥";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¥\";bonus=x" but got "" +PASS ¦/x (Blob/File) +PASS ¦/x (Request/Response) +PASS x/¦ (Blob/File) +PASS x/¦ (Request/Response) +FAIL x/x;¦=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¦=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¦;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x=¦;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x="¦";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¦\";bonus=x" but got "" +FAIL x/x;x="¦";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¦\";bonus=x" but got "" +PASS §/x (Blob/File) +PASS §/x (Request/Response) +PASS x/§ (Blob/File) +PASS x/§ (Request/Response) +FAIL x/x;§=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;§=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=§;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x=§;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x="§";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"§\";bonus=x" but got "" +FAIL x/x;x="§";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"§\";bonus=x" but got "" +PASS ¨/x (Blob/File) +PASS ¨/x (Request/Response) +PASS x/¨ (Blob/File) +PASS x/¨ (Request/Response) +FAIL x/x;¨=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¨=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¨;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x=¨;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x="¨";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¨\";bonus=x" but got "" +FAIL x/x;x="¨";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¨\";bonus=x" but got "" +PASS ©/x (Blob/File) +PASS ©/x (Request/Response) +PASS x/© (Blob/File) +PASS x/© (Request/Response) +FAIL x/x;©=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;©=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=©;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x=©;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x="©";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"©\";bonus=x" but got "" +FAIL x/x;x="©";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"©\";bonus=x" but got "" +PASS ª/x (Blob/File) +PASS ª/x (Request/Response) +PASS x/ª (Blob/File) +PASS x/ª (Request/Response) +FAIL x/x;ª=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ª=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ª;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x=ª;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x="ª";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ª\";bonus=x" but got "" +FAIL x/x;x="ª";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ª\";bonus=x" but got "" +PASS «/x (Blob/File) +PASS «/x (Request/Response) +PASS x/« (Blob/File) +PASS x/« (Request/Response) +FAIL x/x;«=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;«=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=«;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x=«;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x="«";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"«\";bonus=x" but got "" +FAIL x/x;x="«";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"«\";bonus=x" but got "" +PASS ¬/x (Blob/File) +PASS ¬/x (Request/Response) +PASS x/¬ (Blob/File) +PASS x/¬ (Request/Response) +FAIL x/x;¬=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¬=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¬;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x=¬;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x="¬";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¬\";bonus=x" but got "" +FAIL x/x;x="¬";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¬\";bonus=x" but got "" +PASS /x (Blob/File) +PASS /x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x=;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"\";bonus=x" but got "" +FAIL x/x;x="";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"\";bonus=x" but got "" +PASS ®/x (Blob/File) +PASS ®/x (Request/Response) +PASS x/® (Blob/File) +PASS x/® (Request/Response) +FAIL x/x;®=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;®=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=®;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x=®;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x="®";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"®\";bonus=x" but got "" +FAIL x/x;x="®";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"®\";bonus=x" but got "" +PASS ¯/x (Blob/File) +PASS ¯/x (Request/Response) +PASS x/¯ (Blob/File) +PASS x/¯ (Request/Response) +FAIL x/x;¯=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¯=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¯;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x=¯;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x="¯";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¯\";bonus=x" but got "" +FAIL x/x;x="¯";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¯\";bonus=x" but got "" +PASS °/x (Blob/File) +PASS °/x (Request/Response) +PASS x/° (Blob/File) +PASS x/° (Request/Response) +FAIL x/x;°=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;°=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=°;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x=°;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x="°";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"°\";bonus=x" but got "" +FAIL x/x;x="°";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"°\";bonus=x" but got "" +PASS ±/x (Blob/File) +PASS ±/x (Request/Response) +PASS x/± (Blob/File) +PASS x/± (Request/Response) +FAIL x/x;±=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;±=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=±;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x=±;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x="±";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"±\";bonus=x" but got "" +FAIL x/x;x="±";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"±\";bonus=x" but got "" +PASS ²/x (Blob/File) +PASS ²/x (Request/Response) +PASS x/² (Blob/File) +PASS x/² (Request/Response) +FAIL x/x;²=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;²=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=²;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x=²;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x="²";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"²\";bonus=x" but got "" +FAIL x/x;x="²";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"²\";bonus=x" but got "" +PASS ³/x (Blob/File) +PASS ³/x (Request/Response) +PASS x/³ (Blob/File) +PASS x/³ (Request/Response) +FAIL x/x;³=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;³=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=³;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x=³;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x="³";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"³\";bonus=x" but got "" +FAIL x/x;x="³";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"³\";bonus=x" but got "" +PASS ´/x (Blob/File) +PASS ´/x (Request/Response) +PASS x/´ (Blob/File) +PASS x/´ (Request/Response) +FAIL x/x;´=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;´=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=´;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x=´;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x="´";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"´\";bonus=x" but got "" +FAIL x/x;x="´";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"´\";bonus=x" but got "" +PASS µ/x (Blob/File) +PASS µ/x (Request/Response) +PASS x/µ (Blob/File) +PASS x/µ (Request/Response) +FAIL x/x;µ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;µ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=µ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x=µ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x="µ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"µ\";bonus=x" but got "" +FAIL x/x;x="µ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"µ\";bonus=x" but got "" +PASS ¶/x (Blob/File) +PASS ¶/x (Request/Response) +PASS x/¶ (Blob/File) +PASS x/¶ (Request/Response) +FAIL x/x;¶=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¶=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¶;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x=¶;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x="¶";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¶\";bonus=x" but got "" +FAIL x/x;x="¶";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¶\";bonus=x" but got "" +PASS ·/x (Blob/File) +PASS ·/x (Request/Response) +PASS x/· (Blob/File) +PASS x/· (Request/Response) +FAIL x/x;·=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;·=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=·;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x=·;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x="·";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"·\";bonus=x" but got "" +FAIL x/x;x="·";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"·\";bonus=x" but got "" +PASS ¸/x (Blob/File) +PASS ¸/x (Request/Response) +PASS x/¸ (Blob/File) +PASS x/¸ (Request/Response) +FAIL x/x;¸=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¸=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¸;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x=¸;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x="¸";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¸\";bonus=x" but got "" +FAIL x/x;x="¸";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¸\";bonus=x" but got "" +PASS ¹/x (Blob/File) +PASS ¹/x (Request/Response) +PASS x/¹ (Blob/File) +PASS x/¹ (Request/Response) +FAIL x/x;¹=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¹=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¹;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x=¹;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x="¹";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¹\";bonus=x" but got "" +FAIL x/x;x="¹";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¹\";bonus=x" but got "" +PASS º/x (Blob/File) +PASS º/x (Request/Response) +PASS x/º (Blob/File) +PASS x/º (Request/Response) +FAIL x/x;º=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;º=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=º;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x=º;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x="º";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"º\";bonus=x" but got "" +FAIL x/x;x="º";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"º\";bonus=x" but got "" +PASS »/x (Blob/File) +PASS »/x (Request/Response) +PASS x/» (Blob/File) +PASS x/» (Request/Response) +FAIL x/x;»=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;»=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=»;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x=»;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x="»";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"»\";bonus=x" but got "" +FAIL x/x;x="»";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"»\";bonus=x" but got "" +PASS ¼/x (Blob/File) +PASS ¼/x (Request/Response) +PASS x/¼ (Blob/File) +PASS x/¼ (Request/Response) +FAIL x/x;¼=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¼=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¼;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x=¼;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x="¼";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¼\";bonus=x" but got "" +FAIL x/x;x="¼";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¼\";bonus=x" but got "" +PASS ½/x (Blob/File) +PASS ½/x (Request/Response) +PASS x/½ (Blob/File) +PASS x/½ (Request/Response) +FAIL x/x;½=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;½=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=½;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x=½;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x="½";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"½\";bonus=x" but got "" +FAIL x/x;x="½";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"½\";bonus=x" but got "" +PASS ¾/x (Blob/File) +PASS ¾/x (Request/Response) +PASS x/¾ (Blob/File) +PASS x/¾ (Request/Response) +FAIL x/x;¾=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¾=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¾;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x=¾;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x="¾";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¾\";bonus=x" but got "" +FAIL x/x;x="¾";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¾\";bonus=x" but got "" +PASS ¿/x (Blob/File) +PASS ¿/x (Request/Response) +PASS x/¿ (Blob/File) +PASS x/¿ (Request/Response) +FAIL x/x;¿=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;¿=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=¿;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x=¿;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x="¿";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"¿\";bonus=x" but got "" +FAIL x/x;x="¿";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"¿\";bonus=x" but got "" +PASS À/x (Blob/File) +PASS À/x (Request/Response) +PASS x/À (Blob/File) +PASS x/À (Request/Response) +FAIL x/x;À=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;À=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=À;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x=À;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x="À";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"À\";bonus=x" but got "" +FAIL x/x;x="À";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"À\";bonus=x" but got "" +PASS Á/x (Blob/File) +PASS Á/x (Request/Response) +PASS x/Á (Blob/File) +PASS x/Á (Request/Response) +FAIL x/x;Á=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Á=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Á;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x=Á;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x="Á";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Á\";bonus=x" but got "" +FAIL x/x;x="Á";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Á\";bonus=x" but got "" +PASS Â/x (Blob/File) +PASS Â/x (Request/Response) +PASS x/ (Blob/File) +PASS x/ (Request/Response) +FAIL x/x;Â=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Â=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Â;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x=Â;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x="Â";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Â\";bonus=x" but got "" +FAIL x/x;x="Â";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Â\";bonus=x" but got "" +PASS Ã/x (Blob/File) +PASS Ã/x (Request/Response) +PASS x/à (Blob/File) +PASS x/à (Request/Response) +FAIL x/x;Ã=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ã=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ã;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x=Ã;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x="Ã";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ã\";bonus=x" but got "" +FAIL x/x;x="Ã";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ã\";bonus=x" but got "" +PASS Ä/x (Blob/File) +PASS Ä/x (Request/Response) +PASS x/Ä (Blob/File) +PASS x/Ä (Request/Response) +FAIL x/x;Ä=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ä=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ä;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x=Ä;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x="Ä";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ä\";bonus=x" but got "" +FAIL x/x;x="Ä";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ä\";bonus=x" but got "" +PASS Å/x (Blob/File) +PASS Å/x (Request/Response) +PASS x/Å (Blob/File) +PASS x/Å (Request/Response) +FAIL x/x;Å=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Å=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Å;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x=Å;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x="Å";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Å\";bonus=x" but got "" +FAIL x/x;x="Å";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Å\";bonus=x" but got "" +PASS Æ/x (Blob/File) +PASS Æ/x (Request/Response) +PASS x/Æ (Blob/File) +PASS x/Æ (Request/Response) +FAIL x/x;Æ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Æ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Æ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x=Æ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x="Æ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Æ\";bonus=x" but got "" +FAIL x/x;x="Æ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Æ\";bonus=x" but got "" +PASS Ç/x (Blob/File) +PASS Ç/x (Request/Response) +PASS x/Ç (Blob/File) +PASS x/Ç (Request/Response) +FAIL x/x;Ç=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ç=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ç;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x=Ç;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x="Ç";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ç\";bonus=x" but got "" +FAIL x/x;x="Ç";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ç\";bonus=x" but got "" +PASS È/x (Blob/File) +PASS È/x (Request/Response) +PASS x/È (Blob/File) +PASS x/È (Request/Response) +FAIL x/x;È=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;È=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=È;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x=È;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x="È";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"È\";bonus=x" but got "" +FAIL x/x;x="È";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"È\";bonus=x" but got "" +PASS É/x (Blob/File) +PASS É/x (Request/Response) +PASS x/É (Blob/File) +PASS x/É (Request/Response) +FAIL x/x;É=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;É=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=É;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x=É;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x="É";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"É\";bonus=x" but got "" +FAIL x/x;x="É";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"É\";bonus=x" but got "" +PASS Ê/x (Blob/File) +PASS Ê/x (Request/Response) +PASS x/Ê (Blob/File) +PASS x/Ê (Request/Response) +FAIL x/x;Ê=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ê=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ê;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x=Ê;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x="Ê";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ê\";bonus=x" but got "" +FAIL x/x;x="Ê";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ê\";bonus=x" but got "" +PASS Ë/x (Blob/File) +PASS Ë/x (Request/Response) +PASS x/Ë (Blob/File) +PASS x/Ë (Request/Response) +FAIL x/x;Ë=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ë=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ë;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x=Ë;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x="Ë";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ë\";bonus=x" but got "" +FAIL x/x;x="Ë";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ë\";bonus=x" but got "" +PASS Ì/x (Blob/File) +PASS Ì/x (Request/Response) +PASS x/Ì (Blob/File) +PASS x/Ì (Request/Response) +FAIL x/x;Ì=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ì=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ì;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x=Ì;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x="Ì";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ì\";bonus=x" but got "" +FAIL x/x;x="Ì";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ì\";bonus=x" but got "" +PASS Í/x (Blob/File) +PASS Í/x (Request/Response) +PASS x/Í (Blob/File) +PASS x/Í (Request/Response) +FAIL x/x;Í=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Í=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Í;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x=Í;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x="Í";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Í\";bonus=x" but got "" +FAIL x/x;x="Í";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Í\";bonus=x" but got "" +PASS Î/x (Blob/File) +PASS Î/x (Request/Response) +PASS x/Î (Blob/File) +PASS x/Î (Request/Response) +FAIL x/x;Î=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Î=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Î;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x=Î;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x="Î";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Î\";bonus=x" but got "" +FAIL x/x;x="Î";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Î\";bonus=x" but got "" +PASS Ï/x (Blob/File) +PASS Ï/x (Request/Response) +PASS x/Ï (Blob/File) +PASS x/Ï (Request/Response) +FAIL x/x;Ï=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ï=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ï;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x=Ï;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x="Ï";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ï\";bonus=x" but got "" +FAIL x/x;x="Ï";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ï\";bonus=x" but got "" +PASS Ð/x (Blob/File) +PASS Ð/x (Request/Response) +PASS x/Ð (Blob/File) +PASS x/Ð (Request/Response) +FAIL x/x;Ð=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ð=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ð;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x=Ð;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x="Ð";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ð\";bonus=x" but got "" +FAIL x/x;x="Ð";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ð\";bonus=x" but got "" +PASS Ñ/x (Blob/File) +PASS Ñ/x (Request/Response) +PASS x/Ñ (Blob/File) +PASS x/Ñ (Request/Response) +FAIL x/x;Ñ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ñ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ñ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x=Ñ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x="Ñ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ñ\";bonus=x" but got "" +FAIL x/x;x="Ñ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ñ\";bonus=x" but got "" +PASS Ò/x (Blob/File) +PASS Ò/x (Request/Response) +PASS x/Ò (Blob/File) +PASS x/Ò (Request/Response) +FAIL x/x;Ò=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ò=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ò;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x=Ò;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x="Ò";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ò\";bonus=x" but got "" +FAIL x/x;x="Ò";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ò\";bonus=x" but got "" +PASS Ó/x (Blob/File) +PASS Ó/x (Request/Response) +PASS x/Ó (Blob/File) +PASS x/Ó (Request/Response) +FAIL x/x;Ó=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ó=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ó;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x=Ó;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x="Ó";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ó\";bonus=x" but got "" +FAIL x/x;x="Ó";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ó\";bonus=x" but got "" +PASS Ô/x (Blob/File) +PASS Ô/x (Request/Response) +PASS x/Ô (Blob/File) +PASS x/Ô (Request/Response) +FAIL x/x;Ô=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ô=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ô;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x=Ô;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x="Ô";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ô\";bonus=x" but got "" +FAIL x/x;x="Ô";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ô\";bonus=x" but got "" +PASS Õ/x (Blob/File) +PASS Õ/x (Request/Response) +PASS x/Õ (Blob/File) +PASS x/Õ (Request/Response) +FAIL x/x;Õ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Õ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Õ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x=Õ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x="Õ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Õ\";bonus=x" but got "" +FAIL x/x;x="Õ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Õ\";bonus=x" but got "" +PASS Ö/x (Blob/File) +PASS Ö/x (Request/Response) +PASS x/Ö (Blob/File) +PASS x/Ö (Request/Response) +FAIL x/x;Ö=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ö=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ö;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x=Ö;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x="Ö";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ö\";bonus=x" but got "" +FAIL x/x;x="Ö";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ö\";bonus=x" but got "" +PASS ×/x (Blob/File) +PASS ×/x (Request/Response) +PASS x/× (Blob/File) +PASS x/× (Request/Response) +FAIL x/x;×=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;×=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=×;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x=×;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x="×";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"×\";bonus=x" but got "" +FAIL x/x;x="×";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"×\";bonus=x" but got "" +PASS Ø/x (Blob/File) +PASS Ø/x (Request/Response) +PASS x/Ø (Blob/File) +PASS x/Ø (Request/Response) +FAIL x/x;Ø=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ø=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ø;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x=Ø;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x="Ø";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ø\";bonus=x" but got "" +FAIL x/x;x="Ø";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ø\";bonus=x" but got "" +PASS Ù/x (Blob/File) +PASS Ù/x (Request/Response) +PASS x/Ù (Blob/File) +PASS x/Ù (Request/Response) +FAIL x/x;Ù=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ù=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ù;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x=Ù;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x="Ù";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ù\";bonus=x" but got "" +FAIL x/x;x="Ù";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ù\";bonus=x" but got "" +PASS Ú/x (Blob/File) +PASS Ú/x (Request/Response) +PASS x/Ú (Blob/File) +PASS x/Ú (Request/Response) +FAIL x/x;Ú=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ú=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ú;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x=Ú;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x="Ú";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ú\";bonus=x" but got "" +FAIL x/x;x="Ú";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ú\";bonus=x" but got "" +PASS Û/x (Blob/File) +PASS Û/x (Request/Response) +PASS x/Û (Blob/File) +PASS x/Û (Request/Response) +FAIL x/x;Û=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Û=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Û;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x=Û;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x="Û";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Û\";bonus=x" but got "" +FAIL x/x;x="Û";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Û\";bonus=x" but got "" +PASS Ü/x (Blob/File) +PASS Ü/x (Request/Response) +PASS x/Ü (Blob/File) +PASS x/Ü (Request/Response) +FAIL x/x;Ü=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ü=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ü;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x=Ü;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x="Ü";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ü\";bonus=x" but got "" +FAIL x/x;x="Ü";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ü\";bonus=x" but got "" +PASS Ý/x (Blob/File) +PASS Ý/x (Request/Response) +PASS x/Ý (Blob/File) +PASS x/Ý (Request/Response) +FAIL x/x;Ý=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Ý=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Ý;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x=Ý;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x="Ý";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Ý\";bonus=x" but got "" +FAIL x/x;x="Ý";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Ý\";bonus=x" but got "" +PASS Þ/x (Blob/File) +PASS Þ/x (Request/Response) +PASS x/Þ (Blob/File) +PASS x/Þ (Request/Response) +FAIL x/x;Þ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;Þ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=Þ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x=Þ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x="Þ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"Þ\";bonus=x" but got "" +FAIL x/x;x="Þ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"Þ\";bonus=x" but got "" +PASS ß/x (Blob/File) +PASS ß/x (Request/Response) +PASS x/ß (Blob/File) +PASS x/ß (Request/Response) +FAIL x/x;ß=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ß=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ß;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x=ß;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x="ß";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ß\";bonus=x" but got "" +FAIL x/x;x="ß";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ß\";bonus=x" but got "" +PASS à/x (Blob/File) +PASS à/x (Request/Response) +PASS x/à (Blob/File) +PASS x/à (Request/Response) +FAIL x/x;à=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;à=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=à;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x=à;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x="à";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"à\";bonus=x" but got "" +FAIL x/x;x="à";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"à\";bonus=x" but got "" +PASS á/x (Blob/File) +PASS á/x (Request/Response) +PASS x/á (Blob/File) +PASS x/á (Request/Response) +FAIL x/x;á=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;á=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=á;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x=á;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x="á";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"á\";bonus=x" but got "" +FAIL x/x;x="á";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"á\";bonus=x" but got "" +PASS â/x (Blob/File) +PASS â/x (Request/Response) +PASS x/â (Blob/File) +PASS x/â (Request/Response) +FAIL x/x;â=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;â=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=â;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x=â;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x="â";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"â\";bonus=x" but got "" +FAIL x/x;x="â";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"â\";bonus=x" but got "" +PASS ã/x (Blob/File) +PASS ã/x (Request/Response) +PASS x/ã (Blob/File) +PASS x/ã (Request/Response) +FAIL x/x;ã=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ã=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ã;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x=ã;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x="ã";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ã\";bonus=x" but got "" +FAIL x/x;x="ã";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ã\";bonus=x" but got "" +PASS ä/x (Blob/File) +PASS ä/x (Request/Response) +PASS x/ä (Blob/File) +PASS x/ä (Request/Response) +FAIL x/x;ä=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ä=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ä;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x=ä;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x="ä";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ä\";bonus=x" but got "" +FAIL x/x;x="ä";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ä\";bonus=x" but got "" +PASS å/x (Blob/File) +PASS å/x (Request/Response) +PASS x/å (Blob/File) +PASS x/å (Request/Response) +FAIL x/x;å=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;å=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=å;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x=å;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x="å";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"å\";bonus=x" but got "" +FAIL x/x;x="å";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"å\";bonus=x" but got "" +PASS æ/x (Blob/File) +PASS æ/x (Request/Response) +PASS x/æ (Blob/File) +PASS x/æ (Request/Response) +FAIL x/x;æ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;æ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=æ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x=æ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x="æ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"æ\";bonus=x" but got "" +FAIL x/x;x="æ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"æ\";bonus=x" but got "" +PASS ç/x (Blob/File) +PASS ç/x (Request/Response) +PASS x/ç (Blob/File) +PASS x/ç (Request/Response) +FAIL x/x;ç=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ç=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ç;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x=ç;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x="ç";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ç\";bonus=x" but got "" +FAIL x/x;x="ç";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ç\";bonus=x" but got "" +PASS è/x (Blob/File) +PASS è/x (Request/Response) +PASS x/è (Blob/File) +PASS x/è (Request/Response) +FAIL x/x;è=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;è=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=è;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x=è;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x="è";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"è\";bonus=x" but got "" +FAIL x/x;x="è";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"è\";bonus=x" but got "" +PASS é/x (Blob/File) +PASS é/x (Request/Response) +PASS x/é (Blob/File) +PASS x/é (Request/Response) +FAIL x/x;é=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;é=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=é;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x=é;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x="é";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"é\";bonus=x" but got "" +FAIL x/x;x="é";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"é\";bonus=x" but got "" +PASS ê/x (Blob/File) +PASS ê/x (Request/Response) +PASS x/ê (Blob/File) +PASS x/ê (Request/Response) +FAIL x/x;ê=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ê=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ê;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x=ê;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x="ê";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ê\";bonus=x" but got "" +FAIL x/x;x="ê";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ê\";bonus=x" but got "" +PASS ë/x (Blob/File) +PASS ë/x (Request/Response) +PASS x/ë (Blob/File) +PASS x/ë (Request/Response) +FAIL x/x;ë=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ë=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ë;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x=ë;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x="ë";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ë\";bonus=x" but got "" +FAIL x/x;x="ë";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ë\";bonus=x" but got "" +PASS ì/x (Blob/File) +PASS ì/x (Request/Response) +PASS x/ì (Blob/File) +PASS x/ì (Request/Response) +FAIL x/x;ì=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ì=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ì;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x=ì;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x="ì";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ì\";bonus=x" but got "" +FAIL x/x;x="ì";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ì\";bonus=x" but got "" +PASS í/x (Blob/File) +PASS í/x (Request/Response) +PASS x/í (Blob/File) +PASS x/í (Request/Response) +FAIL x/x;í=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;í=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=í;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x=í;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x="í";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"í\";bonus=x" but got "" +FAIL x/x;x="í";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"í\";bonus=x" but got "" +PASS î/x (Blob/File) +PASS î/x (Request/Response) +PASS x/î (Blob/File) +PASS x/î (Request/Response) +FAIL x/x;î=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;î=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=î;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x=î;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x="î";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"î\";bonus=x" but got "" +FAIL x/x;x="î";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"î\";bonus=x" but got "" +PASS ï/x (Blob/File) +PASS ï/x (Request/Response) +PASS x/ï (Blob/File) +PASS x/ï (Request/Response) +FAIL x/x;ï=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ï=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ï;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x=ï;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x="ï";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ï\";bonus=x" but got "" +FAIL x/x;x="ï";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ï\";bonus=x" but got "" +PASS ð/x (Blob/File) +PASS ð/x (Request/Response) +PASS x/ð (Blob/File) +PASS x/ð (Request/Response) +FAIL x/x;ð=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ð=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ð;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x=ð;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x="ð";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ð\";bonus=x" but got "" +FAIL x/x;x="ð";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ð\";bonus=x" but got "" +PASS ñ/x (Blob/File) +PASS ñ/x (Request/Response) +PASS x/ñ (Blob/File) +PASS x/ñ (Request/Response) +FAIL x/x;ñ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ñ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ñ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x=ñ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x="ñ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ñ\";bonus=x" but got "" +FAIL x/x;x="ñ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ñ\";bonus=x" but got "" +PASS ò/x (Blob/File) +PASS ò/x (Request/Response) +PASS x/ò (Blob/File) +PASS x/ò (Request/Response) +FAIL x/x;ò=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ò=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ò;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x=ò;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x="ò";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ò\";bonus=x" but got "" +FAIL x/x;x="ò";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ò\";bonus=x" but got "" +PASS ó/x (Blob/File) +PASS ó/x (Request/Response) +PASS x/ó (Blob/File) +PASS x/ó (Request/Response) +FAIL x/x;ó=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ó=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ó;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x=ó;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x="ó";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ó\";bonus=x" but got "" +FAIL x/x;x="ó";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ó\";bonus=x" but got "" +PASS ô/x (Blob/File) +PASS ô/x (Request/Response) +PASS x/ô (Blob/File) +PASS x/ô (Request/Response) +FAIL x/x;ô=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ô=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ô;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x=ô;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x="ô";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ô\";bonus=x" but got "" +FAIL x/x;x="ô";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ô\";bonus=x" but got "" +PASS õ/x (Blob/File) +PASS õ/x (Request/Response) +PASS x/õ (Blob/File) +PASS x/õ (Request/Response) +FAIL x/x;õ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;õ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=õ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x=õ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x="õ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"õ\";bonus=x" but got "" +FAIL x/x;x="õ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"õ\";bonus=x" but got "" +PASS ö/x (Blob/File) +PASS ö/x (Request/Response) +PASS x/ö (Blob/File) +PASS x/ö (Request/Response) +FAIL x/x;ö=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ö=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ö;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x=ö;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x="ö";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ö\";bonus=x" but got "" +FAIL x/x;x="ö";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ö\";bonus=x" but got "" +PASS ÷/x (Blob/File) +PASS ÷/x (Request/Response) +PASS x/÷ (Blob/File) +PASS x/÷ (Request/Response) +FAIL x/x;÷=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;÷=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=÷;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x=÷;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x="÷";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"÷\";bonus=x" but got "" +FAIL x/x;x="÷";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"÷\";bonus=x" but got "" +PASS ø/x (Blob/File) +PASS ø/x (Request/Response) +PASS x/ø (Blob/File) +PASS x/ø (Request/Response) +FAIL x/x;ø=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ø=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ø;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x=ø;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x="ø";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ø\";bonus=x" but got "" +FAIL x/x;x="ø";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ø\";bonus=x" but got "" +PASS ù/x (Blob/File) +PASS ù/x (Request/Response) +PASS x/ù (Blob/File) +PASS x/ù (Request/Response) +FAIL x/x;ù=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ù=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ù;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x=ù;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x="ù";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ù\";bonus=x" but got "" +FAIL x/x;x="ù";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ù\";bonus=x" but got "" +PASS ú/x (Blob/File) +PASS ú/x (Request/Response) +PASS x/ú (Blob/File) +PASS x/ú (Request/Response) +FAIL x/x;ú=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ú=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ú;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x=ú;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x="ú";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ú\";bonus=x" but got "" +FAIL x/x;x="ú";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ú\";bonus=x" but got "" +PASS û/x (Blob/File) +PASS û/x (Request/Response) +PASS x/û (Blob/File) +PASS x/û (Request/Response) +FAIL x/x;û=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;û=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=û;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x=û;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x="û";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"û\";bonus=x" but got "" +FAIL x/x;x="û";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"û\";bonus=x" but got "" +PASS ü/x (Blob/File) +PASS ü/x (Request/Response) +PASS x/ü (Blob/File) +PASS x/ü (Request/Response) +FAIL x/x;ü=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ü=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ü;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x=ü;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x="ü";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ü\";bonus=x" but got "" +FAIL x/x;x="ü";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ü\";bonus=x" but got "" +PASS ý/x (Blob/File) +PASS ý/x (Request/Response) +PASS x/ý (Blob/File) +PASS x/ý (Request/Response) +FAIL x/x;ý=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ý=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ý;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x=ý;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x="ý";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ý\";bonus=x" but got "" +FAIL x/x;x="ý";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ý\";bonus=x" but got "" +PASS þ/x (Blob/File) +PASS þ/x (Request/Response) +PASS x/þ (Blob/File) +PASS x/þ (Request/Response) +FAIL x/x;þ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;þ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=þ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x=þ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x="þ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"þ\";bonus=x" but got "" +FAIL x/x;x="þ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"þ\";bonus=x" but got "" +PASS ÿ/x (Blob/File) +PASS ÿ/x (Request/Response) +PASS x/ÿ (Blob/File) +PASS x/ÿ (Request/Response) +FAIL x/x;ÿ=x;bonus=x (Blob/File) assert_equals: Blob expected "x/x;bonus=x" but got "" +FAIL x/x;ÿ=x;bonus=x (Request/Response) assert_equals: expected "x/x;bonus=x" but got "" +FAIL x/x;x=ÿ;bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x=ÿ;bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x="ÿ";bonus=x (Blob/File) assert_equals: Blob expected "x/x;x=\"ÿ\";bonus=x" but got "" +FAIL x/x;x="ÿ";bonus=x (Request/Response) assert_equals: expected "x/x;x=\"ÿ\";bonus=x" but got "" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results.html b/third_party/WebKit/LayoutTests/fast/harness/results.html index 71188ab..cddc970 100644 --- a/third_party/WebKit/LayoutTests/fast/harness/results.html +++ b/third_party/WebKit/LayoutTests/fast/harness/results.html
@@ -527,7 +527,7 @@ } let html = ` <div class='expect' tabindex='0' data-id='${test.expectId}'><div class='details'></div>${Report.printFlag(test)}${bug} - ${pathParser.dir}/<a target='test' tabindex='-1' href='${pathParser.testHref}'>${pathParser.file}</a> + ${pathParser.dir}<a target='test' tabindex='-1' href='${pathParser.testHref}'>${pathParser.file}</a> [ ${status} ] </div> `;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp index de29490d..36a7fb0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
@@ -113,8 +113,7 @@ source.StartPosition())); v8::Local<v8::Value> result; { - CachedMetadataHandler* cache_handler = - source.GetResource() ? source.GetResource()->CacheHandler() : nullptr; + CachedMetadataHandler* cache_handler = source.CacheHandler(); V8CacheOptions v8_cache_options = CacheOptions(cache_handler, GetFrame()->GetSettings()); @@ -133,8 +132,8 @@ v8::Local<v8::Script> script; if (!V8ScriptRunner::CompileScript(ScriptState::From(context), source, - cache_handler, access_control_status, - v8_cache_options, referrer_info) + access_control_status, v8_cache_options, + referrer_info) .ToLocal(&script)) return result;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp index 573ba67..54d2f07 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp
@@ -4,6 +4,8 @@ #include "bindings/core/v8/ScriptSourceCode.h" +#include "core/loader/resource/ScriptResource.h" + namespace blink { namespace { @@ -49,9 +51,11 @@ ScriptSourceCode::ScriptSourceCode( const String& source, ScriptSourceLocationType source_location_type, + CachedMetadataHandler* cache_handler, const KURL& url, const TextPosition& start_position) : source_(TreatNullSourceAsEmpty(source)), + cache_handler_(cache_handler), url_(StripFragmentIdentifier(url)), start_position_(start_position), source_location_type_(source_location_type) { @@ -62,7 +66,7 @@ ScriptSourceCode::ScriptSourceCode(ScriptStreamer* streamer, ScriptResource* resource) : source_(TreatNullSourceAsEmpty(resource->SourceText())), - resource_(resource), + cache_handler_(resource->CacheHandler()), streamer_(streamer), url_(StripFragmentIdentifier(resource->GetResponse().Url())), source_map_url_(SourceMapUrlFromResponse(resource->GetResponse())), @@ -72,7 +76,7 @@ ScriptSourceCode::~ScriptSourceCode() {} void ScriptSourceCode::Trace(blink::Visitor* visitor) { - visitor->Trace(resource_); + visitor->Trace(cache_handler_); visitor->Trace(streamer_); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h index 30e8775..36b301b 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
@@ -34,7 +34,6 @@ #include "bindings/core/v8/ScriptSourceLocationType.h" #include "bindings/core/v8/ScriptStreamer.h" #include "core/CoreExport.h" -#include "core/loader/resource/ScriptResource.h" #include "platform/heap/Handle.h" #include "platform/weborigin/KURL.h" #include "platform/wtf/text/TextPosition.h" @@ -42,6 +41,9 @@ namespace blink { +class ScriptResource; +class CachedMetadataHandler; + class CORE_EXPORT ScriptSourceCode final { DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); @@ -50,6 +52,7 @@ ScriptSourceCode( const String& source, ScriptSourceLocationType = ScriptSourceLocationType::kUnknown, + CachedMetadataHandler* cache_handler = nullptr, const KURL& = KURL(), const TextPosition& start_position = TextPosition::MinimumPosition()); @@ -67,7 +70,7 @@ bool IsNull() const { return source_.IsNull(); } const String& Source() const { return source_; } - ScriptResource* GetResource() const { return resource_; } + CachedMetadataHandler* CacheHandler() const { return cache_handler_; } KURL Url() const; int StartLine() const { return start_position_.line_.OneBasedInt(); } const TextPosition& StartPosition() const { return start_position_; } @@ -80,7 +83,7 @@ private: const String source_; - Member<ScriptResource> resource_; + Member<CachedMetadataHandler> cache_handler_; Member<ScriptStreamer> streamer_; const KURL url_; const String source_map_url_;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp index f80bc36..f7287908 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp
@@ -153,10 +153,8 @@ v8::TryCatch try_catch(scope.GetIsolate()); v8::Local<v8::Script> script; EXPECT_TRUE(V8ScriptRunner::CompileScript( - scope.GetScriptState(), source_code, - source_code.GetResource()->CacheHandler(), - kSharableCrossOrigin, kV8CacheOptionsDefault, - ReferrerScriptInfo()) + scope.GetScriptState(), source_code, kSharableCrossOrigin, + kV8CacheOptionsDefault, ReferrerScriptInfo()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -195,10 +193,8 @@ v8::TryCatch try_catch(scope.GetIsolate()); v8::Local<v8::Script> script; EXPECT_FALSE(V8ScriptRunner::CompileScript( - scope.GetScriptState(), source_code, - source_code.GetResource()->CacheHandler(), - kSharableCrossOrigin, kV8CacheOptionsDefault, - ReferrerScriptInfo()) + scope.GetScriptState(), source_code, kSharableCrossOrigin, + kV8CacheOptionsDefault, ReferrerScriptInfo()) .ToLocal(&script)); EXPECT_TRUE(try_catch.HasCaught()); } @@ -350,10 +346,8 @@ v8::TryCatch try_catch(scope.GetIsolate()); v8::Local<v8::Script> script; EXPECT_TRUE(V8ScriptRunner::CompileScript( - scope.GetScriptState(), source_code, - source_code.GetResource()->CacheHandler(), - kSharableCrossOrigin, kV8CacheOptionsDefault, - ReferrerScriptInfo()) + scope.GetScriptState(), source_code, kSharableCrossOrigin, + kV8CacheOptionsDefault, ReferrerScriptInfo()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -389,10 +383,8 @@ v8::TryCatch try_catch(scope.GetIsolate()); v8::Local<v8::Script> script; EXPECT_TRUE(V8ScriptRunner::CompileScript( - scope.GetScriptState(), source_code, - source_code.GetResource()->CacheHandler(), - kSharableCrossOrigin, kV8CacheOptionsDefault, - ReferrerScriptInfo()) + scope.GetScriptState(), source_code, kSharableCrossOrigin, + kV8CacheOptionsDefault, ReferrerScriptInfo()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); } @@ -429,10 +421,8 @@ v8::TryCatch try_catch(scope.GetIsolate()); v8::Local<v8::Script> script; EXPECT_TRUE(V8ScriptRunner::CompileScript( - scope.GetScriptState(), source_code, - source_code.GetResource()->CacheHandler(), - kSharableCrossOrigin, kV8CacheOptionsDefault, - ReferrerScriptInfo()) + scope.GetScriptState(), source_code, kSharableCrossOrigin, + kV8CacheOptionsDefault, ReferrerScriptInfo()) .ToLocal(&script)); EXPECT_FALSE(try_catch.HasCaught()); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp index 8c51a14e..e7dfef8 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -389,7 +389,6 @@ v8::MaybeLocal<v8::Script> V8ScriptRunner::CompileScript( ScriptState* script_state, const ScriptSourceCode& source, - CachedMetadataHandler* cache_metadata_handler, AccessControlStatus access_control_status, V8CacheOptions v8_cache_options, const ReferrerScriptInfo& referrer_info) { @@ -402,7 +401,7 @@ return CompileScript(script_state, V8String(isolate, source.Source()), source.Url(), source.SourceMapUrl(), source.StartPosition(), source.SourceLocationType(), - source.Streamer(), cache_metadata_handler, + source.Streamer(), source.CacheHandler(), access_control_status, v8_cache_options, referrer_info); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h index 99755a2..cd0db2f 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
@@ -67,7 +67,6 @@ // CachedMetadataHandler is set when metadata caching is supported. static v8::MaybeLocal<v8::Script> CompileScript(ScriptState*, const ScriptSourceCode&, - CachedMetadataHandler*, AccessControlStatus, V8CacheOptions, const ReferrerScriptInfo&);
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp index 8c9c887..e851064b 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
@@ -254,7 +254,6 @@ ScriptValue WorkerOrWorkletScriptController::EvaluateInternal( const ScriptSourceCode& source_code, - CachedMetadataHandler* cache_handler, V8CacheOptions v8_cache_options) { TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data", InspectorEvaluateScriptEvent::Data(nullptr, source_code.Url(), @@ -273,8 +272,8 @@ // - a work{er,let} script is always "not parser inserted". ReferrerScriptInfo referrer_info; if (V8ScriptRunner::CompileScript(script_state_.get(), source_code, - cache_handler, kSharableCrossOrigin, - v8_cache_options, referrer_info) + kSharableCrossOrigin, v8_cache_options, + referrer_info) .ToLocal(&compiled_script)) maybe_result = V8ScriptRunner::RunCompiledScript(isolate_, compiled_script, global_scope_); @@ -307,13 +306,12 @@ bool WorkerOrWorkletScriptController::Evaluate( const ScriptSourceCode& source_code, ErrorEvent** error_event, - CachedMetadataHandler* cache_handler, V8CacheOptions v8_cache_options) { if (IsExecutionForbidden()) return false; ExecutionState state(this); - EvaluateInternal(source_code, cache_handler, v8_cache_options); + EvaluateInternal(source_code, v8_cache_options); if (IsExecutionForbidden()) return false; @@ -357,7 +355,7 @@ ScriptValue WorkerOrWorkletScriptController::EvaluateAndReturnValueForTest( const ScriptSourceCode& source_code) { ExecutionState state(this); - return EvaluateInternal(source_code, nullptr, kV8CacheOptionsDefault); + return EvaluateInternal(source_code, kV8CacheOptionsDefault); } void WorkerOrWorkletScriptController::ForbidExecution() {
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h index 6585654..13f7950 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h
@@ -42,7 +42,6 @@ namespace blink { -class CachedMetadataHandler; class ErrorEvent; class ExceptionState; class ScriptSourceCode; @@ -63,7 +62,6 @@ // Returns true if the evaluation completed with no uncaught exception. bool Evaluate(const ScriptSourceCode&, ErrorEvent** = nullptr, - CachedMetadataHandler* = nullptr, V8CacheOptions = kV8CacheOptionsDefault); // Prevents future JavaScript execution. @@ -104,7 +102,6 @@ // Evaluate a script file in the current execution environment. ScriptValue EvaluateInternal(const ScriptSourceCode&, - CachedMetadataHandler*, V8CacheOptions); void DisposeContextIfNeeded();
diff --git a/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp b/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp index 4021e5a..493d049 100644 --- a/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp +++ b/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp
@@ -246,9 +246,9 @@ error_occurred = ErrorOccurred(); if (!is_external_) { - ScriptSourceCode source_code(GetElement()->TextFromChildren(), - source_location_type_, document_url, - StartingPosition()); + ScriptSourceCode source_code( + GetElement()->TextFromChildren(), source_location_type_, + nullptr /* cache_handler */, document_url, StartingPosition()); return ClassicScript::Create(source_code, options_, kSharableCrossOrigin); }
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index 52df9b84..5abc376 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -682,11 +682,10 @@ } // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-script -bool ScriptLoader::FetchClassicScript( - const KURL& url, - Document& element_document, - const ScriptFetchOptions& options, - const WTF::TextEncoding& encoding) { +bool ScriptLoader::FetchClassicScript(const KURL& url, + Document& element_document, + const ScriptFetchOptions& options, + const WTF::TextEncoding& encoding) { FetchParameters::DeferOption defer = FetchParameters::kNoDefer; if (!parser_inserted_ || element_->AsyncAttributeValue() || element_->DeferAttributeValue())
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp index 5c02721..0707e08a 100644 --- a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
@@ -177,9 +177,10 @@ DCHECK(!old_document.GetFrame()); old_context_document = &old_document; } - if (old_context_document != new_context_document) + if (old_context_document != new_context_document) { old_context_document->GetScriptRunner()->MovePendingScript( new_context_document->GetScriptRunner(), script_loader); + } } void ScriptRunner::MovePendingScript(ScriptRunner* new_runner,
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp index e2fff36..853f7da4 100644 --- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -371,9 +371,10 @@ EXPECT_CALL(*script_loaders[0], Execute()) .WillOnce(Invoke([&script_loaders, this] { - for (int i = 2; i < 20; i++) + for (int i = 2; i < 20; i++) { script_runner_->NotifyScriptReady(script_loaders[i], ScriptRunner::kAsync); + } order_.push_back(0); }));
diff --git a/third_party/WebKit/Source/core/exported/WebScriptSource.cpp b/third_party/WebKit/Source/core/exported/WebScriptSource.cpp index ddc320a..92e8546 100644 --- a/third_party/WebKit/Source/core/exported/WebScriptSource.cpp +++ b/third_party/WebKit/Source/core/exported/WebScriptSource.cpp
@@ -12,8 +12,8 @@ WebScriptSource::operator ScriptSourceCode() const { TextPosition position(OrdinalNumber::FromOneBasedInt(start_line), OrdinalNumber::First()); - return ScriptSourceCode(code, ScriptSourceLocationType::kUnknown, url, - position); + return ScriptSourceCode(code, ScriptSourceLocationType::kUnknown, + nullptr /* cache_handler */, url, position); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp index 87dce93..073a767c 100644 --- a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResource.cpp
@@ -48,9 +48,6 @@ params.SetRequestContext(WebURLRequest::kRequestContextStyle); CSSStyleSheetResource* resource = ToCSSStyleSheetResource( fetcher->RequestResource(params, CSSStyleSheetResourceFactory())); - // TODO(kouhei): Dedupe this logic w/ ScriptResource::fetch - if (resource && !params.IntegrityMetadata().IsEmpty()) - resource->SetIntegrityMetadata(params.IntegrityMetadata()); return resource; }
diff --git a/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp b/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp index dd83831..5c97ea5 100644 --- a/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/ScriptResource.cpp
@@ -46,11 +46,8 @@ DCHECK_EQ(params.GetResourceRequest().GetFrameType(), WebURLRequest::kFrameTypeNone); params.SetRequestContext(WebURLRequest::kRequestContextScript); - ScriptResource* resource = ToScriptResource( + return ToScriptResource( fetcher->RequestResource(params, ScriptResourceFactory())); - if (resource && !params.IntegrityMetadata().IsEmpty()) - resource->SetIntegrityMetadata(params.IntegrityMetadata()); - return resource; } ScriptResource::ScriptResource(
diff --git a/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp index 31dd0d4..77a98bc3 100644 --- a/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp +++ b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp
@@ -12,6 +12,7 @@ #include "core/page/Page.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/wait.h" +#include "platform/SharedBuffer.h" #include "platform/testing/UnitTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/Source/core/mojo/tests/JsToCpp.mojom-blink.h"
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index 736d0bc..4338034 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -106,9 +106,9 @@ source_code.length(), cached_meta_data.get() ? cached_meta_data->size() : 0); bool success = ScriptController()->Evaluate( - ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown, + ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown, handler, script_url), - nullptr /* error_event */, handler, v8_cache_options_); + nullptr /* error_event */, v8_cache_options_); ReportingProxy().DidEvaluateWorkerScript(success); } @@ -203,8 +203,8 @@ source_code.length(), cached_meta_data ? cached_meta_data->size() : 0); ScriptController()->Evaluate( ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown, - response_url), - &error_event, handler, v8_cache_options_); + handler, response_url), + &error_event, v8_cache_options_); if (error_event) { ScriptController()->RethrowExceptionFromImportedScript(error_event, exception_state);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp index ecddf0d..db24f1d4 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -462,7 +462,7 @@ if (params.IntegrityMetadata().IsEmpty()) return false; - return !IntegrityMetadata::SetsEqual(integrity_metadata_, + return !IntegrityMetadata::SetsEqual(IntegrityMetadata(), params.IntegrityMetadata()); }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.h b/third_party/WebKit/Source/platform/loader/fetch/Resource.h index b5d96142..8ae3830 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/Resource.h +++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
@@ -254,11 +254,8 @@ bool HasCacheControlNoStoreHeader() const; bool MustReloadDueToVaryHeader(const ResourceRequest& new_request) const; - void SetIntegrityMetadata(const IntegrityMetadataSet& metadata) { - integrity_metadata_ = metadata; - } const IntegrityMetadataSet& IntegrityMetadata() const { - return integrity_metadata_; + return options_.integrity_metadata; } ResourceIntegrityDisposition IntegrityDisposition() const { return integrity_disposition_; @@ -473,7 +470,6 @@ bool detachable_ = false; ResourceIntegrityDisposition integrity_disposition_; - IntegrityMetadataSet integrity_metadata_; SubresourceIntegrity::ReportInfo integrity_report_info_; // Ordered list of all redirects followed while fetching this resource.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py index 3157ce4..ce062d76 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
@@ -5,6 +5,7 @@ import collections import re +from webkitpy.common.memoized import memoized from webkitpy.common.path_finder import PathFinder from webkitpy.common.system.filesystem import FileSystem @@ -16,6 +17,8 @@ # Recognizes 'X@Y' email addresses. Very simplistic. (from owners.py) BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$' +WPT_NOTIFY_REGEXP = r'^# *WPT-NOTIFY: *true$' +COMPONENT_REGEXP = r'^# *COMPONENT: *(.+)$' class DirectoryOwnersExtractor(object): @@ -97,7 +100,7 @@ Returns: A list of valid owners (email addresses). """ - contents = self.filesystem.read_text_file(owners_file) + contents = self._read_text_file(owners_file) email_regexp = re.compile(BASIC_EMAIL_REGEXP) addresses = [] for line in contents.splitlines(): @@ -105,3 +108,34 @@ if email_regexp.match(line): addresses.append(line) return addresses + + def extract_component(self, owners_file): + """Extract the component from an OWNERS file. + + Args: + owners_file: An absolute path to an OWNERS file. + + Returns: + A string, or None if not found. + """ + contents = self._read_text_file(owners_file) + search = re.search(COMPONENT_REGEXP, contents, re.MULTILINE) + if search: + return search.group(1) + return None + + def is_wpt_notify_enabled(self, owners_file): + """Checks if the OWNERS file enables WPT-NOTIFY. + + Args: + owners_file: An absolute path to an OWNERS file. + + Returns: + A boolean. + """ + contents = self._read_text_file(owners_file) + return bool(re.search(WPT_NOTIFY_REGEXP, contents, re.MULTILINE)) + + @memoized + def _read_text_file(self, path): + return self.filesystem.read_text_file(path)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor_unittest.py index 6e72505..2b810c4 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor_unittest.py
@@ -100,3 +100,35 @@ } self.assertEqual(self.extractor.extract_owners(ABS_WPT_BASE + '/foo/OWNERS'), ['foo@chromium.org', 'bar@chromium.org']) + + def test_extract_component(self): + self.filesystem.files = { + ABS_WPT_BASE + '/foo/OWNERS': + '# TEAM: some-team@chromium.org\n' + '# COMPONENT: Blink>Layout\n' + } + self.assertEqual(self.extractor.extract_component(ABS_WPT_BASE + '/foo/OWNERS'), 'Blink>Layout') + + def test_is_wpt_notify_enabled_true(self): + self.filesystem.files = { + ABS_WPT_BASE + '/foo/OWNERS': + '# COMPONENT: Blink>Layout\n' + '# WPT-NOTIFY: true\n' + } + self.assertTrue(self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) + + def test_is_wpt_notify_enabled_false(self): + self.filesystem.files = { + ABS_WPT_BASE + '/foo/OWNERS': + '# COMPONENT: Blink>Layout\n' + '# WPT-NOTIFY: false\n' + } + self.assertFalse(self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) + + def test_is_wpt_notify_enabled_absence_is_false(self): + self.filesystem.files = { + ABS_WPT_BASE + '/foo/OWNERS': + '# TEAM: some-team@chromium.org\n' + '# COMPONENT: Blink>Layout\n' + } + self.assertFalse(self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py index c34b7018..57f85f7 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py
@@ -96,7 +96,7 @@ gerrit_url_with_ps: Gerrit URL of this CL with the patchset number. """ for test_name, changed_baselines in changed_test_baselines.iteritems(): - directory = self._find_owned_directory(test_name) + directory = self.find_owned_directory(test_name) if not directory: _log.warning('Cannot find OWNERS of %s', test_name) continue @@ -126,7 +126,7 @@ be rebaselined to a list of new test expectation lines. """ for test_name, expectation_lines in test_expectations.iteritems(): - directory = self._find_owned_directory(test_name) + directory = self.find_owned_directory(test_name) if not directory: _log.warning('Cannot find OWNERS of %s', test_name) continue @@ -157,9 +157,16 @@ full_directory = self.host.filesystem.join(self.finder.layout_tests_dir(), directory) owners_file = self.host.filesystem.join(full_directory, 'OWNERS') + is_wpt_notify_enabled = self.owners_extractor.is_wpt_notify_enabled(owners_file) + _log.info("WPT-NOTIFY: %s", str(is_wpt_notify_enabled)) + owners = self.owners_extractor.extract_owners(owners_file) _log.info("Owners: %s", ' '.join(owners)) + component = self.owners_extractor.extract_component(owners_file) + # component could be None. + _log.info("Component: %s", str(component)) + prologue = ('WPT import {} introduced new failures in {}:\n\n' 'List of new failures:\n'.format(gerrit_url, directory)) failure_list = '' @@ -195,7 +202,7 @@ commit_list += line + '\n' return commit_list - def _find_owned_directory(self, test_name): + def find_owned_directory(self, test_name): """Finds the lowest directory that contains the test and has OWNERS. Args: @@ -204,6 +211,11 @@ Returns: The path of the found directory relative to LayoutTests. """ + # Always use non-virtual test names when looking up OWNERS. + if self.default_port.lookup_virtual_test_base(test_name): + test_name = self.default_port.lookup_virtual_test_base(test_name) + # find_owners_file takes either a relative path from the *root* of the + # repository, or an absolute path. abs_test_path = self.finder.path_from_layout_tests(test_name) owners_file = self.owners_extractor.find_owners_file(self.host.filesystem.dirname(abs_test_path)) if not owners_file:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py index 5eec76e1..9259f44 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py
@@ -7,6 +7,7 @@ from webkitpy.common.checkout.git_mock import MockGit from webkitpy.common.host_mock import MockHost from webkitpy.common.system.executive_mock import mock_git_commands +from webkitpy.common.system.filesystem_mock import MockFileSystem from webkitpy.w3c.local_wpt_mock import MockLocalWPT from webkitpy.w3c.import_notifier import ImportNotifier, TestFailure from webkitpy.w3c.wpt_expectations_updater import UMBRELLA_BUG @@ -16,6 +17,11 @@ def setUp(self): self.host = MockHost() + # Mock a virtual test suite at virtual/gpu/external/wpt/foo. + self.host.filesystem = MockFileSystem({ + '/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites': + '[{"prefix": "gpu", "base": "external/wpt/foo", "args": ["--foo"]}]' + }) self.git = self.host.git() self.local_wpt = MockLocalWPT() self.notifier = ImportNotifier(self.host, self.git, self.local_wpt) @@ -51,25 +57,23 @@ def test_more_failures_in_baseline_fewer_fails(self): executive = mock_git_commands({ - 'diff': '''diff --git a/foo-expected.txt b/foo-expected.txt ---- a/foo-expected.txt -+++ b/foo-expected.txt --FAIL an old failure --FAIL new failure 1 -+FAIL new failure 2 -''' + 'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n' + '--- a/foo-expected.txt\n' + '+++ b/foo-expected.txt\n' + '-FAIL an old failure\n' + '-FAIL new failure 1\n' + '+FAIL new failure 2\n') }) self.notifier.git = MockGit(executive=executive) self.assertFalse(self.notifier.more_failures_in_baseline('foo-expected.txt')) def test_more_failures_in_baseline_same_fails(self): executive = mock_git_commands({ - 'diff': '''diff --git a/foo-expected.txt b/foo-expected.txt ---- a/foo-expected.txt -+++ b/foo-expected.txt --FAIL an old failure -+FAIL new failure 1 -''' + 'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n' + '--- a/foo-expected.txt\n' + '+++ b/foo-expected.txt\n' + '-FAIL an old failure\n' + '+FAIL a new failure\n') }) self.notifier.git = MockGit(executive=executive) self.assertFalse(self.notifier.more_failures_in_baseline('foo-expected.txt')) @@ -134,6 +138,21 @@ 'Fake subject: https://github.com/w3c/web-platform-tests/commit/SHA2\n' ) + def test_find_owned_directory_non_virtual(self): + self.host.filesystem.write_text_file( + '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + 'test@chromium.org' + ) + self.assertEqual(self.notifier.find_owned_directory('external/wpt/foo/bar.html'), 'external/wpt/foo') + self.assertEqual(self.notifier.find_owned_directory('external/wpt/foo/bar/baz.html'), 'external/wpt/foo') + + def test_find_owned_directory_virtual(self): + self.host.filesystem.write_text_file( + '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + 'test@chromium.org' + ) + self.assertEqual(self.notifier.find_owned_directory('virtual/gpu/external/wpt/foo/bar.html'), 'external/wpt/foo') + def test_test_failure_to_str_baseline_change(self): failure = TestFailure( TestFailure.BASELINE_CHANGE, 'external/wpt/foo/bar.html',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py index a860d1ed..1c9ec8c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -622,9 +622,7 @@ return None def send_notifications(self, local_wpt): - # Check the format of these values. issue = self.git_cl.run(['status', '--field=id']).strip() - # FIXME(robertma): this does not work! https://crbug.com/792611 patchset = self.git_cl.run(['status', '--field=patch']).strip() # Construct the notifier here so that any errors won't affect the import. notifier = ImportNotifier(self.host, self.chromium_git, local_wpt)
diff --git a/third_party/bazel/OWNERS b/third_party/bazel/OWNERS index ea2bde4..aed8b1a 100644 --- a/third_party/bazel/OWNERS +++ b/third_party/bazel/OWNERS
@@ -1,4 +1,4 @@ agrieve@chromium.org -zpeng@chromium.org +jbudorick@chromium.org # COMPONENT: Build
diff --git a/third_party/checkstyle/OWNERS b/third_party/checkstyle/OWNERS index 3daedd9..cf39ee7 100644 --- a/third_party/checkstyle/OWNERS +++ b/third_party/checkstyle/OWNERS
@@ -1,5 +1,3 @@ agrieve@chromium.org jbudorick@chromium.org nyquist@chromium.org -zpeng@chromium.org -
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 79634c9..f864171c 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -25030,6 +25030,7 @@ <int value="-790036192" label="overscroll-start-threshold"/> <int value="-787426248" label="ChromeHomeSurvey:disabled"/> <int value="-780798969" label="disable-single-click-autofill"/> + <int value="-778126349" label="DownloadsLocationChange:enabled"/> <int value="-776686417" label="SiteExplorationUi:disabled"/> <int value="-775321548" label="UseNewDoodleApi:disabled"/> <int value="-772679248" label="MojoVideoEncodeAccelerator:enabled"/> @@ -25629,6 +25630,7 @@ <int value="936341613" label="OfflinePagesCT:disabled"/> <int value="936919953" label="bypass-app-banner-engagement-checks"/> <int value="938191241" label="VrShell:enabled"/> + <int value="939366135" label="DownloadsLocationChange:disabled"/> <int value="939554480" label="enable-credit-card-scan"/> <int value="939603162" label="BackgroundLoadingForDownloads:disabled"/> <int value="941036016" label="ContentSuggestionsSettings:disabled"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index abc68bf..9c9e9b5 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -327,6 +327,12 @@ interaction. This value should be between [0, 100]. </summary> </metric> + <metric name="CheckerboardedImagesCount"> + <summary> + The number of images checker-imaged and re-rasterized during this + interaction. + </summary> + </metric> <metric name="NumMissingTiles"> <summary> The number of visible tiles per frame checkerboarded during this @@ -335,6 +341,18 @@ </metric> </event> +<event name="Compositor.Rendering"> + <owner>khushalsagar@chromium.org</owner> + <summary> + Metrics related to rendering in the compositor. + </summary> + <metric name="CheckerboardedImagesCount"> + <summary> + The number of images checker-imaged and re-rasterized on this page. + </summary> + </metric> +</event> + <event name="ContextualSearch"> <owner>donnd@chromium.org</owner> <summary>
diff --git a/tools/perf/benchmarks/blink_perf_unittest.py b/tools/perf/benchmarks/blink_perf_unittest.py index 0136f58..eef36b3 100644 --- a/tools/perf/benchmarks/blink_perf_unittest.py +++ b/tools/perf/benchmarks/blink_perf_unittest.py
@@ -5,7 +5,6 @@ import unittest from telemetry import story -from telemetry import decorators from telemetry.page import page as page_module from telemetry.testing import options_for_unittests from telemetry.testing import page_test_test_case @@ -39,7 +38,6 @@ story_set.AddStory(page) return story_set - @decorators.Disabled('android') # crbug.com/793063 def testBlinkPerfTracingMetricsForMeasureTime(self): results = self.RunMeasurement(measurement=self._measurement, ps=self._CreateStorySetForTestFile('append-child-measure-time.html'), @@ -62,7 +60,6 @@ self.assertGreater(update_layout_trees[0].GetRepresentativeNumber(), 0.001) - @decorators.Disabled('android') # crbug.com/793063 def testBlinkPerfTracingMetricsForMeasureFrameTime(self): results = self.RunMeasurement(measurement=self._measurement, ps=self._CreateStorySetForTestFile( @@ -87,7 +84,6 @@ self.assertGreater(frame_view_painttrees[0].GetRepresentativeNumber(), 0.001) - @decorators.Disabled('android') # crbug.com/793063 def testBlinkPerfTracingMetricsForMeasurePageLoadTime(self): results = self.RunMeasurement(measurement=self._measurement, ps=self._CreateStorySetForTestFile(
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py index fa22157a..c0117a6d 100644 --- a/tools/perf/benchmarks/v8.py +++ b/tools/perf/benchmarks/v8.py
@@ -30,7 +30,7 @@ def SetExpectations(self): self.DisableStory('Docs (1 open document tab)', [story.expectations.ALL_WIN], - 'crbug.com/') + 'crbug.com/770982') return StoryExpectations()
diff --git a/tools/resources/OWNERS b/tools/resources/OWNERS index b6a4905e..ea259a7 100644 --- a/tools/resources/OWNERS +++ b/tools/resources/OWNERS
@@ -1,3 +1,3 @@ agrieve@chromium.org +per-file filter_resource_whitelist.*=estevenson@chromium.org per-file generate_resource_whitelist.*=estevenson@chromium.org -per-file filter_resource_whitelist.*=zpeng@chromium.org
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index 247879c..d38a202 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn
@@ -230,3 +230,25 @@ # 2nd copy of any code via the component. assert_no_deps = [ "//ui/ozone" ] } + +# X11 backend has its own test suite only built when we are using the x11 +# backend. +if (ozone_platform_x11) { + test("ozone_x11_unittests") { + deps = [ + "//base/test:test_support", + "//mojo/edk/test:run_all_unittests", + "//mojo/public/cpp/bindings", + "//testing/gtest", + "//ui/gfx:test_support", + "//ui/gfx/geometry", + "//ui/ozone/public/interfaces:struct_trait_unit_test", + ] + + deps += [ "platform/x11:x11_unittests" ] + + # Platform tests link ozone statically. Make sure we're not getting a + # 2nd copy of any code via the component. + assert_no_deps = [ "//ui/ozone" ] + } +}
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn index 86d45117..a060b1f 100644 --- a/ui/ozone/platform/x11/BUILD.gn +++ b/ui/ozone/platform/x11/BUILD.gn
@@ -47,3 +47,17 @@ public_configs = [ "//third_party/khronos:khronos_headers" ] } + +source_set("x11_unittests") { + testonly = true + sources = [ + "x11_cursor_factory_ozone_unittest.cc", + ] + + deps = [ + ":x11", + "//testing/gtest", + "//ui/ozone:platform", + "//ui/ozone/common", + ] +}
diff --git a/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc b/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc new file mode 100644 index 0000000..8b065eb --- /dev/null +++ b/ui/ozone/platform/x11/x11_cursor_factory_ozone_unittest.cc
@@ -0,0 +1,31 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/geometry/point.h" + +namespace ui { + +TEST(X11CursorFactoryOzoneTest, InvisibleRefcount) { + X11CursorFactoryOzone factory; + + // Building an image cursor with an invalid SkBitmap should return the + // invisible cursor in X11. The invisible cursor instance should have more + // than a single reference since the factory should hold a reference and + // CreateImageCursor should return an incremented refcount. + X11CursorOzone* invisible_cursor = static_cast<X11CursorOzone*>( + factory.CreateImageCursor(SkBitmap(), gfx::Point(), 1.0f)); + ASSERT_FALSE(invisible_cursor->HasOneRef()); + + // Release our refcount on the cursor + factory.UnrefImageCursor(invisible_cursor); + + // The invisible cursor should still exist. + EXPECT_TRUE(invisible_cursor->HasOneRef()); +} + +} // namespace ui