1// Copyright 2014 The Chromium Authors. All rights reserved.
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 "fake_ppapi/fake_var_manager.h"
6
7#include "gtest/gtest.h"
8
9FakeVarManager::FakeVarManager() : debug(false), next_id_(1) {}
10
11FakeVarManager::~FakeVarManager() {
12  // The ref counts for all vars should be zero.
13  for (VarMap::const_iterator iter = var_map_.begin(); iter != var_map_.end();
14       ++iter) {
15    const FakeVarData& var_data = iter->second;
16    EXPECT_EQ(0, var_data.ref_count) << "Non-zero refcount on "
17                                     << Describe(var_data);
18  }
19}
20
21FakeVarData* FakeVarManager::CreateVarData() {
22  Id id = next_id_++;
23  FakeVarData data;
24  data.id = id;
25  data.ref_count = 1;
26  var_map_[id] = data;
27  return &var_map_[id];
28}
29
30void FakeVarManager::AddRef(PP_Var var) {
31  // From ppb_var.h:
32  //   AddRef() adds a reference to the given var. If this is not a refcounted
33  //   object, this function will do nothing so you can always call it no matter
34  //   what the type.
35
36  FakeVarData* var_data = GetVarData(var);
37  if (!var_data)
38    return;
39
40  EXPECT_GT(var_data->ref_count, 0)
41       << "AddRefing freed " << Describe(*var_data);
42  var_data->ref_count++;
43  if (debug)
44    printf("AddRef of %s [new refcount=%d]\n",
45           Describe(*var_data).c_str(),
46           var_data->ref_count);
47}
48
49std::string FakeVarManager::Describe(const FakeVarData& var_data) {
50  std::stringstream rtn;
51  switch (var_data.type) {
52    case PP_VARTYPE_STRING:
53      rtn << "String with id " << var_data.id <<
54             " with value \"" << var_data.string_value << "\"";
55      break;
56    case PP_VARTYPE_ARRAY:
57      rtn << "Array of size " << var_data.array_value.size()
58          << " with id " << var_data.id;
59      break;
60    case PP_VARTYPE_ARRAY_BUFFER:
61      rtn << "ArrayBuffer of size " << var_data.buffer_value.length
62          << " with id " << var_data.id;
63      break;
64    case PP_VARTYPE_DICTIONARY:
65      rtn << "Dictionary of size " << var_data.dict_value.size() << " with id "
66          << var_data.id;
67      break;
68    default:
69      rtn << "resource of type " << var_data.type
70          << " with id " << var_data.id;
71      break;
72  }
73  return rtn.str();
74}
75
76void FakeVarManager::DestroyVarData(FakeVarData* var_data) {
77  // Release each PP_Var in the array
78
79  switch (var_data->type) {
80    case PP_VARTYPE_ARRAY: {
81      FakeArrayType& vector = var_data->array_value;
82      for (FakeArrayType::iterator it = vector.begin();
83           it != vector.end(); ++it) {
84        Release(*it);
85      }
86      vector.clear();
87      break;
88    }
89    case PP_VARTYPE_ARRAY_BUFFER: {
90      free(var_data->buffer_value.ptr);
91      var_data->buffer_value.ptr = NULL;
92      var_data->buffer_value.length = 0;
93      break;
94    }
95    case PP_VARTYPE_DICTIONARY: {
96      FakeDictType& dict = var_data->dict_value;
97      for (FakeDictType::iterator it = dict.begin();
98           it != dict.end(); it++) {
99        Release(it->second);
100      }
101      dict.clear();
102      break;
103    }
104    default:
105      break;
106  }
107}
108
109FakeVarData* FakeVarManager::GetVarData(PP_Var var) {
110  switch (var.type) {
111    // These types don't have any var data as their data
112    // is stored directly in the var's value union.
113    case PP_VARTYPE_UNDEFINED:
114    case PP_VARTYPE_NULL:
115    case PP_VARTYPE_BOOL:
116    case PP_VARTYPE_INT32:
117    case PP_VARTYPE_DOUBLE:
118      return NULL;
119    default:
120      break;
121  }
122
123  VarMap::iterator iter = var_map_.find(var.value.as_id);
124  if (iter == var_map_.end())
125    return NULL;
126  FakeVarData* var_data = &iter->second;
127  EXPECT_GT(var_data->ref_count, 0)
128      << "Accessing freed " << Describe(*var_data);
129  return var_data;
130}
131
132void FakeVarManager::Release(PP_Var var) {
133  // From ppb_var.h:
134  //   Release() removes a reference to given var, deleting it if the internal
135  //   reference count becomes 0. If the given var is not a refcounted object,
136  //   this function will do nothing so you can always call it no matter what
137  //   the type.
138  FakeVarData* var_data = GetVarData(var);
139  if (!var_data) {
140    if (debug)
141      printf("Releasing simple var\n");
142    return;
143  }
144
145  EXPECT_GT(var_data->ref_count, 0)
146      << "Releasing freed " << Describe(*var_data);
147
148  var_data->ref_count--;
149  if (debug)
150    printf("Released %s [new refcount=%d]\n",
151           Describe(*var_data).c_str(),
152           var_data->ref_count);
153
154  if (var_data->ref_count == 0)
155    DestroyVarData(var_data);
156}
157