Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: extensions/renderer/api_binding_unittest.cc

Issue 2609553003: [Extensions Bindings] Allow custom hooks to return values, throw (Closed)
Patch Set: rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/memory/ptr_util.h" 6 #include "base/memory/ptr_util.h"
7 #include "base/stl_util.h" 7 #include "base/stl_util.h"
8 #include "base/strings/stringprintf.h" 8 #include "base/strings/stringprintf.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "extensions/renderer/api_binding.h" 10 #include "extensions/renderer/api_binding.h"
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 471
472 // Register a hook for the test.oneString method. 472 // Register a hook for the test.oneString method.
473 auto hooks = base::MakeUnique<APIBindingHooks>( 473 auto hooks = base::MakeUnique<APIBindingHooks>(
474 base::Bind(&RunFunctionOnGlobalAndReturnHandle)); 474 base::Bind(&RunFunctionOnGlobalAndReturnHandle));
475 bool did_call = false; 475 bool did_call = false;
476 auto hook = [](bool* did_call, const APISignature* signature, 476 auto hook = [](bool* did_call, const APISignature* signature,
477 v8::Local<v8::Context> context, 477 v8::Local<v8::Context> context,
478 std::vector<v8::Local<v8::Value>>* arguments, 478 std::vector<v8::Local<v8::Value>>* arguments,
479 const ArgumentSpec::RefMap& ref_map) { 479 const ArgumentSpec::RefMap& ref_map) {
480 *did_call = true; 480 *did_call = true;
481 if (arguments->size() != 1u) { 481 APIBindingHooks::RequestResult result(
482 APIBindingHooks::RequestResult::HANDLED);
483 if (arguments->size() != 1u) { // ASSERT* messes with the return type.
482 EXPECT_EQ(1u, arguments->size()); 484 EXPECT_EQ(1u, arguments->size());
483 return APIBindingHooks::RequestResult::HANDLED; 485 return result;
484 } 486 }
485 EXPECT_EQ("foo", gin::V8ToString(arguments->at(0))); 487 EXPECT_EQ("foo", gin::V8ToString(arguments->at(0)));
486 return APIBindingHooks::RequestResult::HANDLED; 488 return result;
487 }; 489 };
488 hooks->RegisterHandleRequest("test.oneString", base::Bind(hook, &did_call)); 490 hooks->RegisterHandleRequest("test.oneString", base::Bind(hook, &did_call));
489 491
490 APIBinding binding( 492 APIBinding binding(
491 "test", functions.get(), nullptr, nullptr, 493 "test", functions.get(), nullptr, nullptr,
492 base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)), 494 base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)),
493 std::move(hooks), &refs); 495 std::move(hooks), &refs);
494 EXPECT_TRUE(refs.empty()); 496 EXPECT_TRUE(refs.empty());
495 497
496 v8::HandleScope handle_scope(isolate()); 498 v8::HandleScope handle_scope(isolate());
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 "(function(obj) { return obj.oneString('ping'); })"); 686 "(function(obj) { return obj.oneString('ping'); })");
685 v8::Local<v8::Value> args[] = {binding_object}; 687 v8::Local<v8::Value> args[] = {binding_object};
686 RunFunctionAndExpectError(function, context, v8::Undefined(isolate()), 688 RunFunctionAndExpectError(function, context, v8::Undefined(isolate()),
687 arraysize(args), args, 689 arraysize(args), args,
688 "Uncaught Error: Custom Hook Error"); 690 "Uncaught Error: Custom Hook Error");
689 691
690 // Other methods, like stringAndInt(), should behave normally. 692 // Other methods, like stringAndInt(), should behave normally.
691 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); 693 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]");
692 } 694 }
693 695
696 // Tests that custom JS hooks can return results synchronously.
697 TEST_F(APIBindingUnittest, TestReturningResultFromCustomJSHook) {
698 // Register a hook for the test.oneString method.
699 auto hooks = base::MakeUnique<APIBindingHooks>(
700 base::Bind(&RunFunctionOnGlobalAndReturnHandle));
701
702 v8::HandleScope handle_scope(isolate());
703 v8::Local<v8::Context> context = ContextLocal();
704 const char kRegisterHook[] =
705 "(function(hooks) {\n"
706 " hooks.setHandleRequest('oneString', str => {\n"
707 " return str + ' pong';\n"
708 " });\n"
709 "})";
710 v8::Local<v8::String> source_string =
711 gin::StringToV8(isolate(), kRegisterHook);
712 v8::Local<v8::String> source_name =
713 gin::StringToV8(isolate(), "custom_hook");
714 hooks->RegisterJsSource(
715 v8::Global<v8::String>(isolate(), source_string),
716 v8::Global<v8::String>(isolate(), source_name));
717
718 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions);
719 ASSERT_TRUE(functions);
720 ArgumentSpec::RefMap refs;
721
722 APIBinding binding(
723 "test", functions.get(), nullptr, nullptr,
724 base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)),
725 std::move(hooks), &refs);
726 EXPECT_TRUE(refs.empty());
727
728 APIEventHandler event_handler(
729 base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
730 v8::Local<v8::Object> binding_object = binding.CreateInstance(
731 context, isolate(), &event_handler, base::Bind(&AllowAllAPIs));
732
733 v8::Local<v8::Function> function =
734 FunctionFromString(context,
735 "(function(obj) { return obj.oneString('ping'); })");
736 v8::Local<v8::Value> args[] = {binding_object};
737 v8::Local<v8::Value> result =
738 RunFunction(function, context, arraysize(args), args);
739 ASSERT_FALSE(result.IsEmpty());
740 std::unique_ptr<base::Value> json_result = V8ToBaseValue(result, context);
741 ASSERT_TRUE(json_result);
742 EXPECT_EQ("\"ping pong\"", ValueToString(*json_result));
743 }
744
745 // Tests that JS custom hooks can throw exceptions for bad invocations.
746 TEST_F(APIBindingUnittest, TestThrowingFromCustomJSHook) {
747 // Our testing handlers for running functions expect a pre-determined success
748 // or failure. Since we're testing throwing exceptions here, we need a way of
749 // running that allows exceptions to be thrown, but we still expect most JS
750 // calls to succeed.
751 // TODO(devlin): This is a bit clunky. If we need to do this enough, we could
752 // figure out a different solution, like having a stack object for allowing
753 // errors/exceptions. But given this is the only place we need it so far, this
754 // is sufficient.
755 auto run_js_and_expect_error = [](v8::Local<v8::Function> function,
756 v8::Local<v8::Context> context,
757 int argc,
758 v8::Local<v8::Value> argv[]) {
759 v8::MaybeLocal<v8::Value> maybe_result =
760 function->Call(context, context->Global(), argc, argv);
761 v8::Global<v8::Value> result;
762 v8::Local<v8::Value> local;
763 if (maybe_result.ToLocal(&local))
764 result.Reset(context->GetIsolate(), local);
765 return result;
766 };
767 // Register a hook for the test.oneString method.
768 auto hooks = base::MakeUnique<APIBindingHooks>(
769 base::Bind(run_js_and_expect_error));
770
771 v8::HandleScope handle_scope(isolate());
772 v8::Local<v8::Context> context = ContextLocal();
773 const char kRegisterHook[] =
774 "(function(hooks) {\n"
775 " hooks.setHandleRequest('oneString', str => {\n"
776 " throw new Error('Custom Hook Error');\n"
777 " });\n"
778 "})";
779 v8::Local<v8::String> source_string =
780 gin::StringToV8(isolate(), kRegisterHook);
781 v8::Local<v8::String> source_name =
782 gin::StringToV8(isolate(), "custom_hook");
783 hooks->RegisterJsSource(
784 v8::Global<v8::String>(isolate(), source_string),
785 v8::Global<v8::String>(isolate(), source_name));
786
787 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions);
788 ASSERT_TRUE(functions);
789 ArgumentSpec::RefMap refs;
790
791 APIBinding binding(
792 "test", functions.get(), nullptr, nullptr,
793 base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)),
794 std::move(hooks), &refs);
795 EXPECT_TRUE(refs.empty());
796
797 APIEventHandler event_handler(
798 base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
799 v8::Local<v8::Object> binding_object = binding.CreateInstance(
800 context, isolate(), &event_handler, base::Bind(&AllowAllAPIs));
801
802 v8::Local<v8::Function> function =
803 FunctionFromString(context,
804 "(function(obj) { return obj.oneString('ping'); })");
805 v8::Local<v8::Value> args[] = {binding_object};
806 RunFunctionAndExpectError(function, context, v8::Undefined(isolate()),
807 arraysize(args), args,
808 "Uncaught Error: Custom Hook Error");
809 }
810
811 // Tests that native custom hooks can return results synchronously, or throw
812 // exceptions for bad invocations.
813 TEST_F(APIBindingUnittest,
814 TestReturningResultAndThrowingExceptionFromCustomNativeHook) {
815 v8::HandleScope handle_scope(isolate());
816 v8::Local<v8::Context> context = ContextLocal();
817
818 // Register a hook for the test.oneString method.
819 auto hooks = base::MakeUnique<APIBindingHooks>(
820 base::Bind(&RunFunctionOnGlobalAndReturnHandle));
821 bool did_call = false;
822 auto hook = [](bool* did_call, const APISignature* signature,
823 v8::Local<v8::Context> context,
824 std::vector<v8::Local<v8::Value>>* arguments,
825 const ArgumentSpec::RefMap& ref_map) {
826 APIBindingHooks::RequestResult result(
827 APIBindingHooks::RequestResult::HANDLED);
828 if (arguments->size() != 1u) { // ASSERT* messes with the return type.
829 EXPECT_EQ(1u, arguments->size());
830 return result;
831 }
832 v8::Isolate* isolate = context->GetIsolate();
833 std::string arg_value = gin::V8ToString(arguments->at(0));
834 if (arg_value == "throw") {
835 isolate->ThrowException(v8::Exception::Error(
836 gin::StringToV8(isolate, "Custom Hook Error")));
837 result.code = APIBindingHooks::RequestResult::THROWN;
838 return result;
839 }
840 result.return_value =
841 gin::StringToV8(context->GetIsolate(), arg_value + " pong");
842 return result;
843 };
844 hooks->RegisterHandleRequest("test.oneString", base::Bind(hook, &did_call));
845
846 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions);
847 ASSERT_TRUE(functions);
848 ArgumentSpec::RefMap refs;
849
850 APIBinding binding(
851 "test", functions.get(), nullptr, nullptr,
852 base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)),
853 std::move(hooks), &refs);
854 EXPECT_TRUE(refs.empty());
855
856 APIEventHandler event_handler(
857 base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
858 v8::Local<v8::Object> binding_object = binding.CreateInstance(
859 context, isolate(), &event_handler, base::Bind(&AllowAllAPIs));
860
861 {
862 // Test an invocation that we expect to throw an exception.
863 v8::Local<v8::Function> function =
864 FunctionFromString(
865 context, "(function(obj) { return obj.oneString('throw'); })");
866 v8::Local<v8::Value> args[] = {binding_object};
867 RunFunctionAndExpectError(function, context, v8::Undefined(isolate()),
868 arraysize(args), args,
869 "Uncaught Error: Custom Hook Error");
870 }
871
872 {
873 // Test an invocation we expect to succeed.
874 v8::Local<v8::Function> function =
875 FunctionFromString(context,
876 "(function(obj) { return obj.oneString('ping'); })");
877 v8::Local<v8::Value> args[] = {binding_object};
878 v8::Local<v8::Value> result =
879 RunFunction(function, context, arraysize(args), args);
880 ASSERT_FALSE(result.IsEmpty());
881 std::unique_ptr<base::Value> json_result = V8ToBaseValue(result, context);
882 ASSERT_TRUE(json_result);
883 EXPECT_EQ("\"ping pong\"", ValueToString(*json_result));
884 }
885 }
886
694 } // namespace extensions 887 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_binding_hooks.cc ('k') | extensions/renderer/api_bindings_system_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698