1// Copyright (c) 2013 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// Unit tests for |Feedback| object.
6
7#include "chrome/browser/spellchecker/feedback.h"
8
9#include "base/strings/utf_string_conversions.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using base::ASCIIToUTF16;
13
14namespace spellcheck {
15
16namespace {
17
18// Identifier for a renderer process.
19const int kRendererProcessId = 7;
20
21// Hash identifier for a misspelling.
22const uint32 kMisspellingHash = 42;
23
24}  // namespace
25
26// A test fixture to help keep the tests simple.
27class FeedbackTest : public testing::Test {
28 public:
29  FeedbackTest() {}
30  virtual ~FeedbackTest() {}
31
32 protected:
33  void AddMisspelling(int renderer_process_id, uint32 hash) {
34    Misspelling misspelling;
35    misspelling.hash = hash;
36    feedback_.AddMisspelling(renderer_process_id, misspelling);
37  }
38
39  spellcheck::Feedback feedback_;
40};
41
42// Should be able to retrieve misspelling after it's added.
43TEST_F(FeedbackTest, RetreiveMisspelling) {
44  EXPECT_EQ(NULL, feedback_.GetMisspelling(kMisspellingHash));
45  AddMisspelling(kRendererProcessId, kMisspellingHash);
46  Misspelling* result = feedback_.GetMisspelling(kMisspellingHash);
47  EXPECT_NE(static_cast<Misspelling*>(NULL), result);
48  EXPECT_EQ(kMisspellingHash, result->hash);
49}
50
51// Removed misspellings should be finalized.
52TEST_F(FeedbackTest, FinalizeRemovedMisspellings) {
53  static const int kRemovedMisspellingHash = 1;
54  static const int kRemainingMisspellingHash = 2;
55  AddMisspelling(kRendererProcessId, kRemovedMisspellingHash);
56  AddMisspelling(kRendererProcessId, kRemainingMisspellingHash);
57  std::vector<uint32> remaining_markers(1, kRemainingMisspellingHash);
58  feedback_.FinalizeRemovedMisspellings(kRendererProcessId, remaining_markers);
59  Misspelling* removed_misspelling =
60      feedback_.GetMisspelling(kRemovedMisspellingHash);
61  EXPECT_NE(static_cast<Misspelling*>(NULL), removed_misspelling);
62  EXPECT_TRUE(removed_misspelling->action.IsFinal());
63  Misspelling* remaining_misspelling =
64      feedback_.GetMisspelling(kRemainingMisspellingHash);
65  EXPECT_NE(static_cast<Misspelling*>(NULL), remaining_misspelling);
66  EXPECT_FALSE(remaining_misspelling->action.IsFinal());
67}
68
69// Duplicate misspellings should not be finalized.
70TEST_F(FeedbackTest, DuplicateMisspellingFinalization) {
71  AddMisspelling(kRendererProcessId, kMisspellingHash);
72  AddMisspelling(kRendererProcessId, kMisspellingHash);
73  std::vector<uint32> remaining_markers(1, kMisspellingHash);
74  feedback_.FinalizeRemovedMisspellings(kRendererProcessId, remaining_markers);
75  std::vector<Misspelling> misspellings = feedback_.GetAllMisspellings();
76  EXPECT_EQ(static_cast<size_t>(1), misspellings.size());
77  EXPECT_FALSE(misspellings[0].action.IsFinal());
78}
79
80// Misspellings should be associated with a renderer.
81TEST_F(FeedbackTest, RendererHasMisspellings) {
82  EXPECT_FALSE(feedback_.RendererHasMisspellings(kRendererProcessId));
83  AddMisspelling(kRendererProcessId, kMisspellingHash);
84  EXPECT_TRUE(feedback_.RendererHasMisspellings(kRendererProcessId));
85}
86
87// Should be able to retrieve misspellings in renderer.
88TEST_F(FeedbackTest, GetMisspellingsInRenderer) {
89  AddMisspelling(kRendererProcessId, kMisspellingHash);
90  const std::vector<Misspelling>& renderer_with_misspellings =
91      feedback_.GetMisspellingsInRenderer(kRendererProcessId);
92  EXPECT_EQ(static_cast<size_t>(1), renderer_with_misspellings.size());
93  EXPECT_EQ(kMisspellingHash, renderer_with_misspellings[0].hash);
94  const std::vector<Misspelling>& renderer_without_misspellings =
95      feedback_.GetMisspellingsInRenderer(kRendererProcessId + 1);
96  EXPECT_EQ(static_cast<size_t>(0), renderer_without_misspellings.size());
97}
98
99// Finalized misspellings should be erased.
100TEST_F(FeedbackTest, EraseFinalizedMisspellings) {
101  AddMisspelling(kRendererProcessId, kMisspellingHash);
102  feedback_.FinalizeRemovedMisspellings(kRendererProcessId,
103                                        std::vector<uint32>());
104  EXPECT_TRUE(feedback_.RendererHasMisspellings(kRendererProcessId));
105  feedback_.EraseFinalizedMisspellings(kRendererProcessId);
106  EXPECT_FALSE(feedback_.RendererHasMisspellings(kRendererProcessId));
107  EXPECT_TRUE(feedback_.GetMisspellingsInRenderer(kRendererProcessId).empty());
108}
109
110// Should be able to check for misspelling existence.
111TEST_F(FeedbackTest, HasMisspelling) {
112  EXPECT_FALSE(feedback_.HasMisspelling(kMisspellingHash));
113  AddMisspelling(kRendererProcessId, kMisspellingHash);
114  EXPECT_TRUE(feedback_.HasMisspelling(kMisspellingHash));
115}
116
117// Should be able to check for feedback data presence.
118TEST_F(FeedbackTest, EmptyFeedback) {
119  EXPECT_TRUE(feedback_.Empty());
120  AddMisspelling(kRendererProcessId, kMisspellingHash);
121  EXPECT_FALSE(feedback_.Empty());
122}
123
124// Should be able to retrieve a list of all renderers with misspellings.
125TEST_F(FeedbackTest, GetRendersWithMisspellings) {
126  EXPECT_TRUE(feedback_.GetRendersWithMisspellings().empty());
127  AddMisspelling(kRendererProcessId, kMisspellingHash);
128  AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
129  std::vector<int> result = feedback_.GetRendersWithMisspellings();
130  EXPECT_EQ(static_cast<size_t>(2), result.size());
131  EXPECT_NE(result[0], result[1]);
132  EXPECT_TRUE(result[0] == kRendererProcessId ||
133              result[0] == kRendererProcessId + 1);
134  EXPECT_TRUE(result[1] == kRendererProcessId ||
135              result[1] == kRendererProcessId + 1);
136}
137
138// Should be able to finalize all misspellings.
139TEST_F(FeedbackTest, FinalizeAllMisspellings) {
140  AddMisspelling(kRendererProcessId, kMisspellingHash);
141  AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
142  {
143    std::vector<Misspelling> pending = feedback_.GetAllMisspellings();
144    for (std::vector<Misspelling>::const_iterator it = pending.begin();
145         it != pending.end();
146         ++it) {
147      EXPECT_FALSE(it->action.IsFinal());
148    }
149  }
150  feedback_.FinalizeAllMisspellings();
151  {
152    std::vector<Misspelling> final = feedback_.GetAllMisspellings();
153    for (std::vector<Misspelling>::const_iterator it = final.begin();
154         it != final.end();
155         ++it) {
156      EXPECT_TRUE(it->action.IsFinal());
157    }
158  }
159}
160
161// Should be able to retrieve a copy of all misspellings.
162TEST_F(FeedbackTest, GetAllMisspellings) {
163  EXPECT_TRUE(feedback_.GetAllMisspellings().empty());
164  AddMisspelling(kRendererProcessId, kMisspellingHash);
165  AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
166  const std::vector<Misspelling>& result = feedback_.GetAllMisspellings();
167  EXPECT_EQ(static_cast<size_t>(2), result.size());
168  EXPECT_NE(result[0].hash, result[1].hash);
169  EXPECT_TRUE(result[0].hash == kMisspellingHash ||
170              result[0].hash == kMisspellingHash + 1);
171  EXPECT_TRUE(result[1].hash == kMisspellingHash ||
172              result[1].hash == kMisspellingHash + 1);
173}
174
175// Should be able to clear all misspellings.
176TEST_F(FeedbackTest, ClearFeedback) {
177  AddMisspelling(kRendererProcessId, kMisspellingHash);
178  AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
179  EXPECT_FALSE(feedback_.Empty());
180  feedback_.Clear();
181  EXPECT_TRUE(feedback_.Empty());
182}
183
184// Should be able to find misspellings by misspelled word.
185TEST_F(FeedbackTest, FindMisspellingsByText) {
186  static const base::string16 kMisspelledText =
187      ASCIIToUTF16("Helllo world. Helllo world");
188  static const base::string16 kSuggestion = ASCIIToUTF16("Hello");
189  static const int kMisspellingStart = 0;
190  static const int kMisspellingLength = 6;
191  static const int kSentenceLength = 14;
192  static const int kNumberOfSentences = 2;
193  static const int kNumberOfRenderers = 2;
194  uint32 hash = kMisspellingHash;
195  for (int renderer_process_id = kRendererProcessId;
196       renderer_process_id < kRendererProcessId + kNumberOfRenderers;
197       ++renderer_process_id) {
198    for (int j = 0; j < kNumberOfSentences; ++j) {
199      feedback_.AddMisspelling(
200          renderer_process_id,
201          Misspelling(kMisspelledText,
202                      kMisspellingStart + j * kSentenceLength,
203                      kMisspellingLength,
204                      std::vector<base::string16>(1, kSuggestion),
205                      ++hash));
206    }
207  }
208
209  static const base::string16 kOtherMisspelledText =
210      ASCIIToUTF16("Somethign else");
211  static const base::string16 kOtherSuggestion = ASCIIToUTF16("Something");
212  static const int kOtherMisspellingStart = 0;
213  static const int kOtherMisspellingLength = 9;
214  feedback_.AddMisspelling(
215      kRendererProcessId,
216      Misspelling(kOtherMisspelledText,
217                  kOtherMisspellingStart,
218                  kOtherMisspellingLength,
219                  std::vector<base::string16>(1, kOtherSuggestion),
220                  hash + 1));
221
222  static const base::string16 kMisspelledWord = ASCIIToUTF16("Helllo");
223  const std::set<uint32>& misspellings =
224      feedback_.FindMisspellings(kMisspelledWord);
225  EXPECT_EQ(static_cast<size_t>(kNumberOfSentences * kNumberOfRenderers),
226            misspellings.size());
227
228  for (std::set<uint32>::const_iterator it = misspellings.begin();
229       it != misspellings.end();
230      ++it) {
231    Misspelling* misspelling = feedback_.GetMisspelling(*it);
232    EXPECT_NE(static_cast<Misspelling*>(NULL), misspelling);
233    EXPECT_TRUE(misspelling->hash >= kMisspellingHash &&
234                misspelling->hash <= hash);
235    EXPECT_EQ(kMisspelledWord, misspelling->GetMisspelledString());
236  }
237}
238
239// Should not be able to find misspellings by misspelled word after they have
240// been removed.
241TEST_F(FeedbackTest, CannotFindMisspellingsByTextAfterErased) {
242  static const base::string16 kMisspelledText = ASCIIToUTF16("Helllo world");
243  static const base::string16 kMisspelledWord = ASCIIToUTF16("Helllo");
244  static const base::string16 kSuggestion = ASCIIToUTF16("Hello");
245  static const int kMisspellingStart = 0;
246  static const int kMisspellingLength = 6;
247  feedback_.AddMisspelling(
248      kRendererProcessId,
249      Misspelling(kMisspelledText,
250                  kMisspellingStart,
251                  kMisspellingLength,
252                  std::vector<base::string16>(1, kSuggestion),
253                  kMisspellingHash));
254  feedback_.GetMisspelling(kMisspellingHash)->action.Finalize();
255  feedback_.EraseFinalizedMisspellings(kRendererProcessId);
256  EXPECT_TRUE(feedback_.FindMisspellings(kMisspelledWord).empty());
257}
258
259}  // namespace spellcheck
260