1   /**
2    * Redistribution  and use  in source  and binary  forms, with  or without
3    * modification, are permitted provided  that the following conditions are
4    * met :
5    *
6    * . Redistributions  of  source  code  must  retain  the  above copyright
7    *   notice, this list of conditions and the following disclaimer.
8    *
9    * . Redistributions in  binary form  must reproduce  the above  copyright
10   *   notice, this list of conditions  and the following disclaimer in  the
11   *   documentation and/or other materials provided with the distribution.
12   *
13   * . The name of the author may not be used to endorse or promote products
14   *   derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS  PROVIDED BY THE  AUTHOR ``AS IS''  AND ANY EXPRESS  OR
17   * IMPLIED  WARRANTIES,  INCLUDING,  BUT   NOT  LIMITED  TO,  THE   IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE ARE
19   * DISCLAIMED.  IN NO  EVENT SHALL  THE AUTHOR  BE LIABLE  FOR ANY  DIRECT,
20   * INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL  DAMAGES
21   * (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT OF  SUBSTITUTE  GOODS OR
22   * SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR  BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN  CONTRACT,
24   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE, EVEN  IF  ADVISED OF  THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   *
28   * $Id: $
29   */
30  
31  package cppncss.counter;
32  
33  import java.io.StringReader;
34  import junit.framework.TestCase;
35  import cppast.AstTranslationUnit;
36  import cppast.Node;
37  import cppast.ParseException;
38  import cppast.Parser;
39  
40  /**
41   * @author Mathieu Champlon
42   */
43  public class FunctionNameExtractorTest extends TestCase
44  {
45      private String extract( final String data ) throws ParseException
46      {
47          final Node node = new Parser( new StringReader( data ) ).translation_unit();
48          return (String)node.jjtAccept( new FunctionNameExtractor(), null );
49      }
50  
51      public void testNotFunctionReturnsNull() throws ParseException
52      {
53          assertNull( extract( "" ) );
54      }
55  
56      public void testFunctionDefinitionWithoutParameters() throws ParseException
57      {
58          assertEquals( "MyFunction()", extract( "void MyFunction() {}" ) );
59      }
60  
61      public void testFunctionDefinitionWithIntegerParameter() throws ParseException
62      {
63          assertEquals( "MyFunction( int )", extract( "void MyFunction( int p ) {}" ) );
64      }
65  
66      public void testFunctionDefinitionWithIntegerParameterWithoutParameterName() throws ParseException
67      {
68          assertEquals( "MyFunction( int )", extract( "void MyFunction( int ) {}" ) );
69      }
70  
71      public void testFunctionDefinitionWithIntegerPointerParameter() throws ParseException
72      {
73          assertEquals( "MyFunction( int* )", extract( "void MyFunction( int* p ) {}" ) );
74      }
75  
76      public void testFunctionDefinitionWithIntegerPointerParameterWithoutParameterName() throws ParseException
77      {
78          assertEquals( "MyFunction( int* )", extract( "void MyFunction( int* ) {}" ) );
79      }
80  
81      public void testFunctionDefinitionWithIntegerReferencePointerConstParameter() throws ParseException
82      {
83          assertEquals( "MyFunction( int*& )", extract( "void MyFunction( int*& p ) {}" ) );
84      }
85  
86      public void testFunctionDefinitionWithIntegerReferencePointerConstParameterWithoutParameterName()
87              throws ParseException
88      {
89          assertEquals( "MyFunction( int*& )", extract( "void MyFunction( int*& ) {}" ) );
90      }
91  
92      public void testFunctionDefinitionWithConstPointerConstParameter() throws ParseException
93      {
94          assertEquals( "MyFunction( const int* const )", extract( "void MyFunction( const int* const p ) {}" ) );
95      }
96  
97      public void testFunctionDefinitionWithConstPointerConstParameterWithoutParameterName() throws ParseException
98      {
99          assertEquals( "MyFunction( const int* const )", extract( "void MyFunction( const int* const ) {}" ) );
100     }
101 
102     public void testFunctionDefinitionWithUnsignedIntegerParameter() throws ParseException
103     {
104         assertEquals( "MyFunction( unsigned int )", extract( "void MyFunction( unsigned int p ) {}" ) );
105     }
106 
107     public void testFunctionDefinitionWithUnsignedIntegerParameterWithoutParameterName() throws ParseException
108     {
109         assertEquals( "MyFunction( unsigned int )", extract( "void MyFunction( unsigned int ) {}" ) );
110     }
111 
112     public void testFunctionDefinitionWithUnsignedIntegerPointerParameter() throws ParseException
113     {
114         assertEquals( "MyFunction( unsigned int* )", extract( "void MyFunction( unsigned int* p ) {}" ) );
115     }
116 
117     public void testFunctionDefinitionWithUnsignedIntegerPointerParameterWithoutParameterName() throws ParseException
118     {
119         assertEquals( "MyFunction( unsigned int* )", extract( "void MyFunction( unsigned int* ) {}" ) );
120     }
121 
122     public void testFunctionDefinitionWithSeveralParameters() throws ParseException
123     {
124         assertEquals( "MyFunction( int, float&, const char* )",
125                 extract( "void MyFunction( int p1, float& p2, const char* p3 ) {}" ) );
126     }
127 
128     public void testFunctionDefinitionWithSeveralParametersWithoutParameterNames() throws ParseException
129     {
130         assertEquals( "MyFunction( int, float&, const char* )",
131                 extract( "void MyFunction( int, float&, const char* ) {}" ) );
132     }
133 
134     public void testConstMethodDefinition() throws ParseException
135     {
136         assertEquals( "MyClass::MyMethod()", extract( "void MyClass::MyMethod() const {}" ) );
137     }
138 
139     public void testMethodDefinitionWithConstReferenceReturnType() throws ParseException
140     {
141         assertEquals( "MyClass::MyMethod()", extract( "const MyType& MyClass::MyMethod() {}" ) );
142     }
143 
144     public void testEqualityOperatorDefinition() throws ParseException
145     {
146         assertEquals( "MyClass::operator ==( const MyClass& )",
147                 extract( "bool MyClass::operator==( const MyClass& rhs ) const {}" ) );
148     }
149 
150     public void testConversionOperatorDefinition() throws ParseException
151     {
152         assertEquals( "MyClass::operator const unsigned char*()",
153                 extract( "MyClass::operator const unsigned char*() const {}" ) );
154     }
155 
156     public void testConstructorDefinition() throws ParseException
157     {
158         assertEquals( "MyClass::MyClass()", extract( "MyClass::MyClass() {}" ) );
159     }
160 
161     public void testConstructorDefinitionWithParameter() throws ParseException
162     {
163         assertEquals( "MyClass::MyClass( int )", extract( "MyClass::MyClass( int p ) {}" ) );
164     }
165 
166     public void testDestructorDefinition() throws ParseException
167     {
168         assertEquals( "MyClass::~MyClass()", extract( "MyClass::~MyClass() {}" ) );
169     }
170 
171     public void testFunctionBodyDoesNotAlterFunctionSignature() throws ParseException
172     {
173         assertEquals( "MyFunction()", extract( "void MyFunction() { char *p; }" ) );
174     }
175 
176     public void testArrayArgument() throws ParseException
177     {
178         assertEquals( "MyFunction( MyType[3] )", extract( "void MyFunction( MyType p[3] ) {}" ) );
179     }
180 
181     public void testArrayArgumentWithoutParameterName() throws ParseException
182     {
183         assertEquals( "MyFunction( MyType[3] )", extract( "void MyFunction( MyType[3] ) {}" ) );
184     }
185 
186     public void testTemplateClassMethod() throws ParseException
187     {
188         assertEquals( "MyClass< T, F >::MyMethod()", extract( "void MyClass< T, F >::MyMethod() {}" ) );
189     }
190 
191     public void testTemplateParameterFunction() throws ParseException
192     {
193         assertEquals( "MyFunction( MyClass< T, F >& )", extract( "void MyFunction( MyClass< T, F >& p ) {}" ) );
194     }
195 
196     public void testTemplateParameterFunctionWithoutParameterName() throws ParseException
197     {
198         assertEquals( "MyFunction( MyClass< T, F >& )", extract( "void MyFunction( MyClass< T, F >& ) {}" ) );
199     }
200 
201     public void testPointerOnMemberParameterFunction() throws ParseException
202     {
203         assertEquals( "MyFunction( void (C::*)( char, float ) )",
204                 extract( "void MyFunction( void (C::*M)( char, float ) ) {}" ) );
205     }
206 
207     public void testPointerOnFunctionParameterFunction() throws ParseException
208     {
209         assertEquals( "MyFunction( void (*)( char, float ) )",
210                 extract( "void MyFunction( void (*F)( char, float ) ) {}" ) );
211     }
212 
213     public void testFunctionReturningPointerOnFunction() throws ParseException
214     {
215         assertEquals( "MyFunction( int )", extract( "void (*MyFunction( int ))( char, float ) {}" ) );
216     }
217 
218     public void testParenthesisOperatorDefinition() throws ParseException
219     {
220         assertEquals( "MyClass::operator()( int )", extract( "void MyClass::operator()( int i ) {}" ) );
221     }
222 
223     public void testFunctionInAnonymousNamespace() throws ParseException
224     {
225         assertEquals( "`anonymous-namespace'::MyFunction()", extract( "namespace { void MyFunction(); }" ) );
226     }
227 
228     public void testMethodOfClassDefinedInFunction() throws ParseException
229     {
230         final String content = "void MyFunction() { class MyClass{ void MyMethod(); }; }";
231         final AstTranslationUnit root = new Parser( new StringReader( content ) ).translation_unit();
232         final Node node = root.jjtGetChild( 0 ).jjtGetChild( 2 ).jjtGetChild( 0 );
233         final String actual = (String)node.jjtAccept( new FunctionNameExtractor(), null );
234         // final String actual = (String)new FunctionNameExtractor().visit( node, null );
235         assertEquals( "MyFunction::MyClass::MyMethod()", actual );
236     }
237 
238     public void testMethodOfClassDefinedLocally() throws ParseException
239     {
240         final String content = "void MyFunction() { { class MyClass{ void MyMethod(); }; } }";
241         final AstTranslationUnit root = new Parser( new StringReader( content ) ).translation_unit();
242         final Node node = root.jjtGetChild( 0 ).jjtGetChild( 2 ).jjtGetChild( 0 );
243         final String actual = (String)node.jjtAccept( new FunctionNameExtractor(), null );
244         // final String actual = (String)new FunctionNameExtractor().visit( node, null );
245         assertEquals( "MyFunction::MyClass::MyMethod()", actual );
246     }
247 }