View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.github.maven_nar.cpptasks;
21  
22  import java.io.File;
23  import java.io.IOException;
24  
25  import org.apache.tools.ant.BuildException;
26  import org.apache.tools.ant.Project;
27  
28  import com.github.maven_nar.cpptasks.compiler.CommandLineCompilerConfiguration;
29  import com.github.maven_nar.cpptasks.compiler.Compiler;
30  import com.github.maven_nar.cpptasks.compiler.LinkType;
31  import com.github.maven_nar.cpptasks.gcc.GccCCompiler;
32  import com.github.maven_nar.cpptasks.msvc.MsvcCCompiler;
33  import com.github.maven_nar.cpptasks.types.CompilerArgument;
34  import com.github.maven_nar.cpptasks.types.ConditionalPath;
35  import com.github.maven_nar.cpptasks.types.DefineArgument;
36  import com.github.maven_nar.cpptasks.types.DefineSet;
37  import com.github.maven_nar.cpptasks.types.IncludePath;
38  import com.github.maven_nar.cpptasks.types.SystemIncludePath;
39  import com.github.maven_nar.cpptasks.types.UndefineArgument;
40  
41  /**
42   * Tests for CompilerDef.
43   */
44  public final class TestCompilerDef extends TestProcessorDef {
45    /**
46     * Sets the name attribute.
47     *
48     * @param compiler
49     *          compiler under test
50     * @param name
51     *          compiler name
52     */
53    private static void setCompilerName(final CompilerDef compiler, final String name) {
54      final CompilerEnum compilerName = new CompilerEnum();
55      compilerName.setValue(name);
56      compiler.setName(compilerName);
57    }
58  
59    /**
60     * Constructor.
61     *
62     * @param name
63     *          test name
64     */
65    public TestCompilerDef(final String name) {
66      super(name);
67    }
68  
69    /**
70     * Creates a new processor.
71     *
72     * @return new processor
73     */
74    @Override
75    protected ProcessorDef create() {
76      return new CompilerDef();
77    }
78  
79    /**
80     * Gets the command line arguments that precede filenames.
81     *
82     * This method filters out <i>-m</i> options because they are
83     * platform-specific options of the GNU compiler suite.
84     *
85     * @param processor
86     *          processor under test
87     * @return command line arguments
88     */
89    @Override
90    protected String[] getPreArguments(final ProcessorDef processor) {
91      final String[] result = ((CommandLineCompilerConfiguration) getConfiguration(processor)).getPreArguments();
92  
93      // filter out -m (i.e. platform-specific) options
94      int j = -1;
95      for (int i = 0; i < result.length; i++) {
96        if (result[i].startsWith("-m")) {
97          continue;
98        }
99        if (i != ++j) {
100         result[j] = result[i];
101       }
102     }
103     if (++j == result.length) {
104       return result;
105     }
106     final String[] filtered = new String[j];
107     System.arraycopy(result, 0, filtered, 0, j);
108     return filtered;
109   }
110 
111   /**
112    * Tests that the classname attribute in the base compiler is effective.
113    */
114   public void testExtendsClassname() {
115     final CompilerDef baseCompiler = new CompilerDef();
116     baseCompiler.setClassname("com.github.maven_nar.cpptasks.msvc.MsvcCCompiler");
117     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
118     extendedCompiler.setExceptions(true);
119     final String[] preArgs = getPreArguments(extendedCompiler);
120     assertEquals("/EHsc", preArgs[2]);
121   }
122 
123   /**
124    * Tests that compilerarg's contained in the base compiler definition are
125    * effective.
126    */
127   public void testExtendsCompilerArgs() {
128     final CompilerDef baseLinker = new CompilerDef();
129     final CompilerArgument linkerArg = new CompilerArgument();
130     linkerArg.setValue("/base");
131     baseLinker.addConfiguredCompilerArg(linkerArg);
132     final CompilerDef extendedLinker = (CompilerDef) createExtendedProcessorDef(baseLinker);
133     final String[] preArgs = getPreArguments(extendedLinker);
134     // FREEHEP, passes extra option
135     assertEquals(3, preArgs.length);
136     assertEquals("/base", preArgs[0]);
137   }
138 
139   /**
140    * Tests that defineset's contained in the base compiler definition are
141    * effective.
142    */
143   public void testExtendsDefineSet() {
144     final CompilerDef baseCompiler = new CompilerDef();
145     final DefineSet defSet = new DefineSet();
146     final DefineArgument define = new DefineArgument();
147     define.setName("foo");
148     define.setValue("bar");
149     defSet.addDefine(define);
150     baseCompiler.addConfiguredDefineset(defSet);
151     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
152     final String[] preArgs = getPreArguments(extendedCompiler);
153     // BEGINFREEHEP, passes extra option
154     assertEquals(3, preArgs.length);
155     assertEquals("-Dfoo=bar", preArgs[2]);
156     // ENDFREEHEP
157   }
158 
159   /**
160    * Tests that the extend attribute of the base compiler definition is
161    * effective.
162    */
163   public void testExtendsExceptions() {
164     final CompilerDef baseCompiler = new CompilerDef();
165     baseCompiler.setExceptions(true);
166     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
167     setCompilerName(extendedCompiler, "msvc");
168     final String[] preArgs = getPreArguments(extendedCompiler);
169     assertEquals("/EHsc", preArgs[2]);
170   }
171 
172   /**
173    * Tests if a fileset enclosed in the base compiler definition is effective.
174    *
175    * @throws IOException
176    *           if unable to create or delete a temporary file
177    */
178   public void testExtendsFileSet() throws IOException {
179     super.testExtendsFileSet(File.createTempFile("cpptaskstest", ".cpp"));
180   }
181 
182   /**
183    * Tests that includepath's contained in the base compiler definition are
184    * effective.
185    */
186   public void testExtendsIncludePath() {
187     final CompilerDef baseCompiler = new CompilerDef();
188     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
189     final IncludePath path = baseCompiler.createIncludePath();
190     path.setPath("/tmp");
191     final String[] preArgs = getPreArguments(extendedCompiler);
192     // BEGINFREEHEP, passes extra option
193     assertEquals(3, preArgs.length);
194     assertEquals("-I", preArgs[2].substring(0, 2));
195     // ENDFREEHEP
196   }
197 
198   /**
199    * Tests that the multithread attribute of the base compiler definition is
200    * effective.
201    */
202   public void testExtendsMultithreaded() {
203     final CompilerDef baseCompiler = new CompilerDef();
204     baseCompiler.setMultithreaded(false);
205     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
206     setCompilerName(extendedCompiler, "msvc");
207     final CCTask cctask = new CCTask();
208     final LinkType linkType = new LinkType();
209     final File objDir = new File("dummy");
210     cctask.setObjdir(objDir);
211     linkType.setStaticRuntime(true);
212     final CommandLineCompilerConfiguration config = (CommandLineCompilerConfiguration) extendedCompiler
213         .createConfiguration(cctask, linkType, null, null, null);
214     final String[] preArgs = config.getPreArguments();
215     assertEquals("/ML", preArgs[3]);
216   }
217 
218   /**
219    * Tests that the name attribute in the base compiler is effective.
220    */
221   public void testExtendsName() {
222     final CompilerDef baseCompiler = new CompilerDef();
223     setCompilerName(baseCompiler, "msvc");
224     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
225     extendedCompiler.setExceptions(true);
226     final String[] preArgs = getPreArguments(extendedCompiler);
227     assertEquals("/EHsc", preArgs[2]);
228   }
229 
230   /**
231    * Tests if the rebuild attribute of the base compiler definition is
232    * effective.
233    *
234    */
235   public void testExtendsRebuild() {
236     testExtendsRebuild(new CompilerDef());
237   }
238 
239   /**
240    * Tests that sysincludepath's contained in the base compiler definition are
241    * effective.
242    */
243   public void testExtendsSysIncludePath() {
244     final CompilerDef baseCompiler = new CompilerDef();
245     final CompilerDef extendedCompiler = (CompilerDef) createExtendedProcessorDef(baseCompiler);
246     final SystemIncludePath path = baseCompiler.createSysIncludePath();
247     path.setPath("/tmp");
248     final String[] preArgs = getPreArguments(extendedCompiler);
249     System.out.println("Class: " + baseCompiler + " and: " + extendedCompiler);
250     // BEGINFREEHEP, passes extra option
251     assertEquals(3, preArgs.length);
252     assertEquals("-isystem", preArgs[2].substring(0, 8));
253     // ENDFREEHEP
254   }
255 
256   /**
257    * This method tests CompilerDef.getActiveDefines.
258    *
259    * A CompilerDef is created similar to what would be created for
260    *
261    * <cc><defineset><define name="DEBUG" if="debug"/> <define name="NDEBUG"
262    * unless="debug"/> </defineset> </cc>
263    *
264    * Then getActiveDefines is called for a project without and with the
265    * "debug" property defined. Return value from getActiveDefines should
266    * contain one member
267    */
268   public void testGetActiveDefines() {
269     final Project project = new org.apache.tools.ant.Project();
270     final CompilerDef def = new CompilerDef();
271     def.setProject(project);
272     final DefineSet defset = new DefineSet();
273     final DefineArgument arg1 = new DefineArgument();
274     arg1.setName("DEBUG");
275     arg1.setIf("debug");
276     defset.addDefine(arg1);
277     final DefineArgument arg2 = new DefineArgument();
278     arg2.setName("NDEBUG");
279     arg2.setUnless("debug");
280     defset.addDefine(arg2);
281     def.addConfiguredDefineset(defset);
282     //
283     // Evaluate without "debug" set
284     //
285     UndefineArgument[] activeArgs = def.getActiveDefines();
286     assertEquals(1, activeArgs.length);
287     assertEquals("NDEBUG", activeArgs[0].getName());
288     //
289     // Set the "debug" property
290     //
291     project.setProperty("debug", "");
292     activeArgs = def.getActiveDefines();
293     assertEquals(1, activeArgs.length);
294     assertEquals("DEBUG", activeArgs[0].getName());
295   }
296 
297   /**
298    * This method tests CompilerDef.getActiveIncludePath.
299    *
300    * A CompilerDef is created similar to what would be created for
301    *
302    * <cc><includepath location=".." if="debug"/> </cc>
303    *
304    * and is evaluate for a project without and without "debug" set
305    */
306   public void testGetActiveIncludePaths() {
307     final Project project = new org.apache.tools.ant.Project();
308     final CompilerDef def = new CompilerDef();
309     def.setProject(project);
310     final ConditionalPath path = def.createIncludePath();
311     path.setLocation(new File(".."));
312     path.setIf("debug");
313     //
314     // Evaluate without "debug" set
315     //
316     String[] includePaths = def.getActiveIncludePaths();
317     assertEquals(0, includePaths.length);
318     //
319     // Set the "debug" property
320     //
321     project.setProperty("debug", "");
322     includePaths = def.getActiveIncludePaths();
323     assertEquals(1, includePaths.length);
324   }
325 
326   /**
327    * Tests that setting classname to the Gcc compiler is effective.
328    */
329   public void testGetGcc() {
330     final CompilerDef compilerDef = (CompilerDef) create();
331     compilerDef.setClassname("com.github.maven_nar.cpptasks.gcc.GccCCompiler");
332     final Compiler comp = (Compiler) compilerDef.getProcessor();
333     assertNotNull(comp);
334     assertSame(GccCCompiler.getInstance(), comp);
335   }
336 
337   /**
338    * Tests that setting classname to the MSVC compiler is effective.
339    */
340   public void testGetMSVC() {
341     final CompilerDef compilerDef = (CompilerDef) create();
342     compilerDef.setClassname("com.github.maven_nar.cpptasks.msvc.MsvcCCompiler");
343     final Compiler comp = (Compiler) compilerDef.getProcessor();
344     assertNotNull(comp);
345     assertSame(MsvcCCompiler.getInstance(), comp);
346   }
347 
348   /**
349    * Tests that setting classname to an bogus class name results in a
350    * BuildException.
351    */
352   public void testUnknownClass() {
353     final CompilerDef compilerDef = (CompilerDef) create();
354     try {
355       compilerDef.setClassname("com.github.maven_nar.cpptasks.bogus.BogusCompiler");
356     } catch (final BuildException ex) {
357       return;
358     }
359     fail("Exception not thrown");
360   }
361 
362   /**
363    * Test that setting classname to a class that doesn't support Compiler
364    * throws a BuildException.
365    *
366    */
367   public void testWrongType() {
368     final CompilerDef compilerDef = (CompilerDef) create();
369     try {
370       compilerDef.setClassname("com.github.maven_nar.cpptasks.msvc.MsvcLinker");
371     } catch (final BuildException ex) {
372       return;
373     }
374     fail("Exception not thrown");
375   }
376 }