@@ -166,6 +166,37 @@ class MockLM : public LanguageModel {
166166 bool hasUnigrams (const std::string&) override { return true ; }
167167};
168168
169+ class SingleReadingCountingLM : public LanguageModel {
170+ public:
171+ std::vector<Unigram> getUnigrams (const std::string& reading) override {
172+ ++getUnigramsCount_;
173+ ++getUnigramsCounts_[reading];
174+ if (reading.find (ReadingGrid::kDefaultSeparator ) != std::string::npos) {
175+ return {};
176+ }
177+ return std::vector<Unigram>{Unigram (reading, -1 )};
178+ }
179+
180+ bool hasUnigrams (const std::string& reading) override {
181+ ++hasUnigramsCount_;
182+ return reading.find (ReadingGrid::kDefaultSeparator ) == std::string::npos;
183+ }
184+
185+ [[nodiscard]] size_t getUnigramsCount () const { return getUnigramsCount_; }
186+
187+ [[nodiscard]] size_t getUnigramsCount (const std::string& reading) const {
188+ auto iter = getUnigramsCounts_.find (reading);
189+ return iter == getUnigramsCounts_.end () ? 0 : iter->second ;
190+ }
191+
192+ [[nodiscard]] size_t hasUnigramsCount () const { return hasUnigramsCount_; }
193+
194+ private:
195+ std::map<std::string, size_t > getUnigramsCounts_;
196+ size_t getUnigramsCount_ = 0 ;
197+ size_t hasUnigramsCount_ = 0 ;
198+ };
199+
169200static bool Contains (const std::vector<ReadingGrid::Candidate>& candidates,
170201 const std::string& str) {
171202 return std::any_of (candidates.cbegin (), candidates.cend (),
@@ -269,6 +300,94 @@ TEST(ReadingGridTest, BasicOperations) {
269300 ASSERT_EQ (grid.spans ().size (), 0 );
270301}
271302
303+ TEST (ReadingGridTest, InsertReadingQueriesEachCombinationOnce) {
304+ auto lm = std::make_shared<SingleReadingCountingLM>();
305+ ReadingGrid grid (lm);
306+
307+ for (const char * reading : {" a" , " b" , " c" , " d" , " e" , " f" }) {
308+ ASSERT_TRUE (grid.insertReading (reading));
309+ }
310+
311+ EXPECT_EQ (lm->getUnigramsCount (), 21 );
312+ EXPECT_EQ (lm->hasUnigramsCount (), 0 );
313+ EXPECT_EQ (lm->getUnigramsCount (" a-b" ), 1 );
314+ EXPECT_EQ (lm->getUnigramsCount (" a-b-c-d-e-f" ), 1 );
315+ EXPECT_EQ (lm->getUnigramsCount (" e-f" ), 1 );
316+ }
317+
318+ TEST (ReadingGridTest, InsertionOnlyQueriesSpansContainingTheEdit) {
319+ auto lm = std::make_shared<SingleReadingCountingLM>();
320+ ReadingGrid grid (lm);
321+ ASSERT_TRUE (grid.insertReading (" a" ));
322+ ASSERT_TRUE (grid.insertReading (" b" ));
323+ ASSERT_TRUE (grid.insertReading (" c" ));
324+
325+ grid.setCursor (1 );
326+ ASSERT_TRUE (grid.insertReading (" x" ));
327+
328+ EXPECT_EQ (lm->getUnigramsCount (), 12 );
329+ EXPECT_EQ (lm->getUnigramsCount (" b-c" ), 1 );
330+ EXPECT_EQ (lm->getUnigramsCount (" a-x" ), 1 );
331+ EXPECT_EQ (lm->getUnigramsCount (" a-x-b-c" ), 1 );
332+ EXPECT_EQ (lm->getUnigramsCount (" x-b-c" ), 1 );
333+ }
334+
335+ TEST (ReadingGridTest, InsertionAtBeginningPreservesExistingLookupResults) {
336+ auto lm = std::make_shared<SingleReadingCountingLM>();
337+ ReadingGrid grid (lm);
338+ ASSERT_TRUE (grid.insertReading (" b" ));
339+ ASSERT_TRUE (grid.insertReading (" c" ));
340+
341+ grid.setCursor (0 );
342+ ASSERT_TRUE (grid.insertReading (" a" ));
343+
344+ EXPECT_EQ (lm->getUnigramsCount (), 6 );
345+ EXPECT_EQ (lm->getUnigramsCount (" b-c" ), 1 );
346+ EXPECT_EQ (lm->getUnigramsCount (" a-b" ), 1 );
347+ EXPECT_EQ (lm->getUnigramsCount (" a-b-c" ), 1 );
348+ }
349+
350+ TEST (ReadingGridTest, DeletionOnlyQueriesSpansCrossingTheEdit) {
351+ auto lm = std::make_shared<SingleReadingCountingLM>();
352+ ReadingGrid grid (lm);
353+ ASSERT_TRUE (grid.insertReading (" a" ));
354+ ASSERT_TRUE (grid.insertReading (" b" ));
355+ ASSERT_TRUE (grid.insertReading (" c" ));
356+ ASSERT_TRUE (grid.insertReading (" d" ));
357+
358+ grid.setCursor (2 );
359+ ASSERT_TRUE (grid.deleteReadingBeforeCursor ());
360+
361+ EXPECT_EQ (lm->getUnigramsCount (), 12 );
362+ EXPECT_EQ (lm->getUnigramsCount (" a-c" ), 1 );
363+ EXPECT_EQ (lm->getUnigramsCount (" a-c-d" ), 1 );
364+ EXPECT_EQ (lm->getUnigramsCount (" c-d" ), 1 );
365+
366+ grid.setCursor (0 );
367+ ASSERT_TRUE (grid.deleteReadingAfterCursor ());
368+ EXPECT_EQ (lm->getUnigramsCount (), 12 );
369+ ASSERT_EQ (grid.readings (), (std::vector<std::string>{" c" , " d" }));
370+ ASSERT_NE (grid.spans ()[0 ].nodeOf (1 ), nullptr );
371+ EXPECT_EQ (grid.spans ()[0 ].nodeOf (1 )->reading (), " c" );
372+
373+ grid.setCursor (2 );
374+ ASSERT_TRUE (grid.deleteReadingBeforeCursor ());
375+ EXPECT_EQ (lm->getUnigramsCount (), 12 );
376+ ASSERT_EQ (grid.readings (), (std::vector<std::string>{" c" }));
377+ ASSERT_NE (grid.spans ()[0 ].nodeOf (1 ), nullptr );
378+ EXPECT_EQ (grid.spans ()[0 ].nodeOf (1 )->reading (), " c" );
379+ }
380+
381+ TEST (ReadingGridTest, InsertReadingAcceptsReadingOwnedByGrid) {
382+ ReadingGrid grid (std::make_shared<MockLM>());
383+ ASSERT_TRUE (grid.insertReading (" a" ));
384+
385+ const std::string& aliasedReading = grid.readings ()[0 ];
386+ ASSERT_TRUE (grid.insertReading (aliasedReading));
387+ ASSERT_EQ (grid.readings (), (std::vector<std::string>{" a" , " a" }));
388+ ASSERT_EQ (grid.spans ()[1 ].nodeOf (1 )->reading (), " a" );
389+ }
390+
272391TEST (ReadingGridTest, InvalidOperations) {
273392 class TestLM : public LanguageModel {
274393 public:
0 commit comments