This patch combine three patch which is related to "--gcov" flag.
[platform/framework/web/chromium-efl.git] / gin / interceptor_unittest.cc
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gin/interceptor.h"
6
7 #include <stdint.h>
8
9 #include "base/functional/bind.h"
10 #include "gin/arguments.h"
11 #include "gin/handle.h"
12 #include "gin/object_template_builder.h"
13 #include "gin/per_isolate_data.h"
14 #include "gin/public/isolate_holder.h"
15 #include "gin/test/v8_test.h"
16 #include "gin/try_catch.h"
17 #include "gin/wrappable.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "v8/include/v8-function.h"
20 #include "v8/include/v8-script.h"
21 #include "v8/include/v8-util.h"
22
23 namespace gin {
24
25 class MyInterceptor : public Wrappable<MyInterceptor>,
26                       public NamedPropertyInterceptor,
27                       public IndexedPropertyInterceptor {
28  public:
29   MyInterceptor(const MyInterceptor&) = delete;
30   MyInterceptor& operator=(const MyInterceptor&) = delete;
31
32   static WrapperInfo kWrapperInfo;
33
34   static gin::Handle<MyInterceptor> Create(v8::Isolate* isolate) {
35     return CreateHandle(isolate, new MyInterceptor(isolate));
36   }
37
38   int value() const { return value_; }
39   void set_value(int value) { value_ = value; }
40
41   // gin::NamedPropertyInterceptor
42   v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate,
43                                         const std::string& property) override {
44     if (property == "value") {
45       return ConvertToV8(isolate, value_);
46     } else if (property == "func") {
47       v8::Local<v8::Context> context = isolate->GetCurrentContext();
48       return GetFunctionTemplate(isolate, "func")
49           ->GetFunction(context)
50           .ToLocalChecked();
51     } else {
52       return v8::Local<v8::Value>();
53     }
54   }
55   bool SetNamedProperty(v8::Isolate* isolate,
56                         const std::string& property,
57                         v8::Local<v8::Value> value) override {
58     if (property == "value") {
59       ConvertFromV8(isolate, value, &value_);
60       return true;
61     }
62     return false;
63   }
64   std::vector<std::string> EnumerateNamedProperties(
65       v8::Isolate* isolate) override {
66     std::vector<std::string> result;
67     result.push_back("func");
68     result.push_back("value");
69     return result;
70   }
71
72   // gin::IndexedPropertyInterceptor
73   v8::Local<v8::Value> GetIndexedProperty(v8::Isolate* isolate,
74                                           uint32_t index) override {
75     if (index == 0)
76       return ConvertToV8(isolate, value_);
77     return v8::Local<v8::Value>();
78   }
79   bool SetIndexedProperty(v8::Isolate* isolate,
80                           uint32_t index,
81                           v8::Local<v8::Value> value) override {
82     if (index == 0) {
83       ConvertFromV8(isolate, value, &value_);
84       return true;
85     }
86     // Don't allow bypassing the interceptor.
87     return true;
88   }
89   std::vector<uint32_t> EnumerateIndexedProperties(
90       v8::Isolate* isolate) override {
91     std::vector<uint32_t> result;
92     result.push_back(0);
93     return result;
94   }
95
96  private:
97   explicit MyInterceptor(v8::Isolate* isolate)
98       : NamedPropertyInterceptor(isolate, this),
99         IndexedPropertyInterceptor(isolate, this),
100         value_(0),
101         template_cache_(isolate) {}
102   ~MyInterceptor() override = default;
103
104   // gin::Wrappable
105   ObjectTemplateBuilder GetObjectTemplateBuilder(
106       v8::Isolate* isolate) override {
107     return Wrappable<MyInterceptor>::GetObjectTemplateBuilder(isolate)
108         .AddNamedPropertyInterceptor()
109         .AddIndexedPropertyInterceptor();
110   }
111
112   int Call(int value) {
113     int tmp = value_;
114     value_ = value;
115     return tmp;
116   }
117
118   v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate,
119                                                       const std::string& name) {
120     v8::Local<v8::FunctionTemplate> function_template =
121         template_cache_.Get(name);
122     if (!function_template.IsEmpty())
123       return function_template;
124     function_template = CreateFunctionTemplate(
125         isolate, base::BindRepeating(&MyInterceptor::Call),
126         InvokerOptions{true, nullptr});
127     template_cache_.Set(name, function_template);
128     return function_template;
129   }
130
131   int value_;
132
133   v8::StdGlobalValueMap<std::string, v8::FunctionTemplate> template_cache_;
134 };
135
136 WrapperInfo MyInterceptor::kWrapperInfo = {kEmbedderNativeGin};
137
138 class InterceptorTest : public V8Test {
139  public:
140   void RunInterceptorTest(const std::string& script_source) {
141     v8::Isolate* isolate = instance_->isolate();
142     v8::HandleScope handle_scope(isolate);
143
144     gin::Handle<MyInterceptor> obj = MyInterceptor::Create(isolate);
145
146     obj->set_value(42);
147     EXPECT_EQ(42, obj->value());
148
149     v8::Local<v8::String> source = StringToV8(isolate, script_source);
150     EXPECT_FALSE(source.IsEmpty());
151
152     gin::TryCatch try_catch(isolate);
153     v8::Local<v8::Script> script =
154         v8::Script::Compile(context_.Get(isolate), source).ToLocalChecked();
155     v8::Local<v8::Value> val =
156         script->Run(context_.Get(isolate)).ToLocalChecked();
157     EXPECT_FALSE(val.IsEmpty());
158     v8::Local<v8::Function> func;
159     EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
160     v8::Local<v8::Value> argv[] = {
161         ConvertToV8(isolate, obj.get()).ToLocalChecked(),
162     };
163     func->Call(context_.Get(isolate), v8::Undefined(isolate), 1, argv)
164         .ToLocalChecked();
165     EXPECT_FALSE(try_catch.HasCaught());
166     EXPECT_EQ("", try_catch.GetStackTrace());
167
168     EXPECT_EQ(191, obj->value());
169   }
170 };
171
172 TEST_F(InterceptorTest, NamedInterceptor) {
173   RunInterceptorTest(
174       "(function (obj) {"
175       "   if (obj.value !== 42) throw 'FAIL';"
176       "   else obj.value = 191; })");
177 }
178
179 TEST_F(InterceptorTest, NamedInterceptorCall) {
180   RunInterceptorTest(
181       "(function (obj) {"
182       "   if (obj.func(191) !== 42) throw 'FAIL';"
183       "   })");
184 }
185
186 TEST_F(InterceptorTest, IndexedInterceptor) {
187   RunInterceptorTest(
188       "(function (obj) {"
189       "   if (obj[0] !== 42) throw 'FAIL';"
190       "   else obj[0] = 191; })");
191 }
192
193 TEST_F(InterceptorTest, BypassInterceptorAllowed) {
194   RunInterceptorTest(
195       "(function (obj) {"
196       "   obj.value = 191 /* make test happy */;"
197       "   obj.foo = 23;"
198       "   if (obj.foo !== 23) throw 'FAIL'; })");
199 }
200
201 TEST_F(InterceptorTest, BypassInterceptorForbidden) {
202   RunInterceptorTest(
203       "(function (obj) {"
204       "   obj.value = 191 /* make test happy */;"
205       "   obj[1] = 23;"
206       "   if (obj[1] === 23) throw 'FAIL'; })");
207 }
208
209 }  // namespace gin