diff --git a/cpp/ycm/Candidate.cpp b/cpp/ycm/Candidate.cpp index 2f925326..25f2ee8d 100644 --- a/cpp/ycm/Candidate.cpp +++ b/cpp/ycm/Candidate.cpp @@ -28,21 +28,6 @@ namespace YouCompleteMe { namespace { -std::string GetWordBoundaryChars( const std::string &text ) { - std::string result; - - for ( uint i = 0; i < text.size(); ++i ) { - if ( i == 0 || - IsUppercase( text[ i ] ) || - ( i > 0 && text[ i - 1 ] == '_' && isalpha( text[ i ] ) ) - ) { - result.push_back( tolower( text[ i ] ) ); - } - } - - return result; -} - LetterNode *FirstUppercaseNode( const std::list< LetterNode *> &list ) { LetterNode *node = NULL; foreach( LetterNode * current_node, list ) { @@ -67,6 +52,28 @@ LetterNode *FirstLowercaseNode( const std::list< LetterNode *> &list ) { } // unnamed namespace +std::string GetWordBoundaryChars( const std::string &text ) { + std::string result; + + for ( uint i = 0; i < text.size(); ++i ) { + bool is_first_char_but_not_underscore = i == 0 && text[ i ] != '_'; + bool is_good_uppercase = i > 0 && + IsUppercase( text[ i ] ) && + !IsUppercase( text[ i - 1 ] ); + bool is_alpha_after_underscore = i > 0 && + text[ i - 1 ] == '_' && + isalpha( text[ i ] ); + + if ( is_first_char_but_not_underscore || + is_good_uppercase || + is_alpha_after_underscore ) { + result.push_back( tolower( text[ i ] ) ); + } + } + + return result; +} + Bitset LetterBitsetFromString( const std::string &text ) { Bitset letter_bitset; diff --git a/cpp/ycm/Candidate.h b/cpp/ycm/Candidate.h index e68dfdac..99e43ed0 100644 --- a/cpp/ycm/Candidate.h +++ b/cpp/ycm/Candidate.h @@ -34,6 +34,9 @@ typedef std::bitset< NUM_LETTERS > Bitset; Bitset LetterBitsetFromString( const std::string &text ); +// Public for tests +std::string GetWordBoundaryChars( const std::string &text ); + class Candidate : boost::noncopyable { public: diff --git a/cpp/ycm/tests/Candidate_test.cpp b/cpp/ycm/tests/Candidate_test.cpp index ef6c2222..91507fc7 100644 --- a/cpp/ycm/tests/Candidate_test.cpp +++ b/cpp/ycm/tests/Candidate_test.cpp @@ -21,6 +21,78 @@ namespace YouCompleteMe { +TEST( GetWordBoundaryCharsTest, SimpleOneWord ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "simple" ) ); +} + +TEST( GetWordBoundaryCharsTest, UnderscoreInMiddle ) { + EXPECT_EQ( "sf", GetWordBoundaryChars( "simple_foo" ) ); +} + +TEST( GetWordBoundaryCharsTest, UnderscoreStart ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "_simple" ) ); +} + +TEST( GetWordBoundaryCharsTest, ManyUnderscoreStart ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "___simple" ) ); +} + +TEST( GetWordBoundaryCharsTest, UnderscoreStartAndInMiddle ) { + EXPECT_EQ( "sf", GetWordBoundaryChars( "_simple_foo" ) ); +} + +TEST( GetWordBoundaryCharsTest, ManyUnderscoreStartAndInMiddle ) { + EXPECT_EQ( "sf", GetWordBoundaryChars( "___simple__foo" ) ); +} + +TEST( GetWordBoundaryCharsTest, SimpleCapitalStart ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "Simple" ) ); +} + +TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWord ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "SimpleStuff" ) ); +} + +TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWordUnderscoreMiddle ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "Simple_Stuff" ) ); +} + +TEST( GetWordBoundaryCharsTest, JavaCase ) { + EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleStuffFoo" ) ); +} + +TEST( GetWordBoundaryCharsTest, UppercaseSequence ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFF" ) ); +} + +TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddle ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFFfoo" ) ); +} + +TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddleUnderscore ) { + EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_Foo" ) ); +} + +TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddleUnderscoreLowercase ) { + EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_foo" ) ); +} + +TEST( GetWordBoundaryCharsTest, AllCapsSimple ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "SIMPLE" ) ); +} + +TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreStart ) { + EXPECT_EQ( "s", GetWordBoundaryChars( "_SIMPLE" ) ); +} + +TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreMiddle ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "SIMPLE_STUFF" ) ); +} + +TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreMiddleAndStart ) { + EXPECT_EQ( "ss", GetWordBoundaryChars( "_SIMPLE_STUFF" ) ); +} + TEST( CandidateTest, TextValid ) { std::string text = "foo"; Candidate candidate( text ); diff --git a/cpp/ycm/tests/IdentifierCompleter_test.cpp b/cpp/ycm/tests/IdentifierCompleter_test.cpp index d8a519a8..924810a3 100644 --- a/cpp/ycm/tests/IdentifierCompleter_test.cpp +++ b/cpp/ycm/tests/IdentifierCompleter_test.cpp @@ -207,6 +207,15 @@ TEST( IdentifierCompleterTest, SameLowercaseCandidateWins ) { "Foobar" ) ); } +TEST( IdentifierCompleterTest, ShorterAndLowercaseWins ) { + EXPECT_THAT( IdentifierCompleter( + StringVector( + "STDIN_FILENO", + "stdin" ) ).CandidatesForQuery( "std" ), + ElementsAre( "stdin", + "STDIN_FILENO" ) ); +} + // TODO: tests for filepath and filetype candidate storing } // namespace YouCompleteMe