/*
* The Apache Software License, Version 1.1
*
* Copyright (C) 2000-2002 The Apache Software Foundation. All rights
* reserved.
* Copyright (C) 2010 John Lewis
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package net.sourceforge.cobertura.test;
import groovy.util.AntBuilder;
import groovy.util.Node;
import net.sourceforge.cobertura.ant.ReportTask;
import net.sourceforge.cobertura.test.util.TestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.taskdefs.Java;
import org.junit.Test;
import java.io.File;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class SwitchFunctionalTest extends AbstractCoberturaTestCase {
AntBuilder ant = TestUtils.getCoberturaAntBuilder(TestUtils
.getCoberturaClassDir());
@Test
public void noDefaultTest() throws Exception {
/*
* Use a temporary directory and create a Main.java source file that
* has a switch statement with no default.
*/
mainSourceFile.getParentFile().mkdirs();
/*
* Note that if the code below is changed, the line numbers in the
* asserts at the bottom of this method will likely need to be adjusted.
*/
FileUtils
.write(
mainSourceFile,
"\n package mypackage;"
+ "\n "
+ "\n public class Main {"
+ "\n public void callNoDefaultSwitch() {"
+ "\n int i=2;"
+ "\n switch (i) {"
+ "\n case 1:"
+ "\n System.out.println(\"1\");"
+ "\n break;"
+ "\n case 2:"
+ "\n System.out.println(\"2\");"
+ "\n break;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchFallThrough() {"
+ "\n switchFallThrough(5);"
+ "\n switchFallThrough(1);"
+ "\n }"
+ "\n "
+ "\n private void switchFallThrough(int i) {"
+ "\n switch (i) {"
+ "\n case 2:"
+ "\n System.out.println(\"2\");"
+ "\n break;"
+ "\n case 3:"
+ "\n break;"
+ "\n case 1: // fall-through!"
+ "\n default:"
+ "\n System.out.println(\"1 or default\");"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithDefault() {"
+ "\n switchWithDefault(15);"
+ "\n }"
+ "\n "
+ "\n private void switchWithDefault(int i) {"
+ "\n switch (i) {"
+ "\n case 15:"
+ "\n System.out.println(\"1\");"
+ "\n break;"
+ "\n case 16:"
+ "\n System.out.println(\"2\");"
+ "\n break;"
+ "\n case 17:"
+ "\n System.out.println(\"3\");"
+ "\n break;"
+ "\n case 18:"
+ "\n System.out.println(\"4\");"
+ "\n break;"
+ "\n // intentionally skip 19 and 20"
+ "\n case 21:"
+ "\n System.out.println(\"5\");"
+ "\n break;"
+ "\n /*"
+ "\n * The compiler will add cases for any numbers that are skipped."
+ "\n * Note the next two cases are commented out, but the compiler"
+ "\n * adds them to the default case."
+ "\n */"
+ "\n //case 19:"
+ "\n //case 20:"
+ "\n default:"
+ "\n System.out.println(\"default\");"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithoutGaps() {"
+ "\n switchWithoutGaps(1);"
+ "\n }"
+ "\n "
+ "\n private void switchWithoutGaps(int i) {"
+ "\n boolean aBoolean = false;"
+ "\n "
+ "\n switch (i) { // tests assume this is line 76"
+ "\n // these cases have no gaps - the numbers are sequential"
+ "\n case 0:"
+ "\n System.out.println(\"0\");"
+ "\n break;"
+ "\n case 1:"
+ "\n System.out.println(\"1\");"
+ "\n break;"
+ "\n case 2:"
+ "\n System.out.println(\"2\");"
+ "\n break;"
+ "\n default:"
+ "\n System.out.println(\"default\");"
+ "\n break;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithoutGapsWithFallThrough() {"
+ "\n switchWithoutGapsWithFallThrough(1);"
+ "\n }"
+ "\n "
+ "\n private void switchWithoutGapsWithFallThrough(int i) {"
+ "\n boolean aBoolean = false;"
+ "\n "
+ "\n switch (i) { // tests assume this is line 100"
+ "\n // these cases have no gaps - the numbers are sequential"
+ "\n case 0:"
+ "\n System.out.println(\"0\");"
+ "\n break;"
+ "\n case 1:"
+ "\n if (aBoolean) {"
+ "\n System.out.println(\"1\");"
+ "\n // the break is intentionally put inside this block to cause a fall-through"
+ "\n break;"
+ "\n }"
+ "\n case 2:"
+ "\n System.out.println(\"2\");"
+ "\n break;"
+ "\n default:"
+ "\n System.out.println(\"default\");"
+ "\n break;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public enum AnEnumeration {"
+ "\n FOO, BAR, GONK"
+ "\n };"
+ "\n "
+ "\n public void callSwitchBug2075537() {"
+ "\n switchBug2075537(AnEnumeration.FOO);"
+ "\n switchBug2075537(AnEnumeration.BAR);"
+ "\n switchBug2075537(AnEnumeration.GONK);"
+ "\n }"
+ "\n "
+ "\n public boolean switchBug2075537(AnEnumeration e) {"
+ "\n // see bug http://sourceforge.net/tracker/?func=detail&aid=2075537&group_id=130558&atid=720015"
+ "\n switch (e) { // tests assume this is line 132"
+ "\n case FOO:"
+ "\n case BAR:"
+ "\n case GONK:"
+ "\n return true;"
+ "\n "
+ "\n default:"
+ "\n return false;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchBug2075537_2() {"
+ "\n switchBug2075537_2(AnEnumeration.FOO);"
+ "\n switchBug2075537_2(AnEnumeration.BAR);"
+ "\n switchBug2075537_2(AnEnumeration.GONK);"
+ "\n }"
+ "\n "
+ "\n public boolean switchBug2075537_2(AnEnumeration e) {"
+ "\n switch (e) { // tests assume this is line 150"
+ "\n case FOO:"
+ "\n return true;"
+ "\n "
+ "\n case BAR:"
+ "\n return true;"
+ "\n "
+ "\n case GONK:"
+ "\n return true;"
+ "\n "
+ "\n default:"
+ "\n return false;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchNonDefaultFallThrough() {"
+ "\n switchNonDefaultFallThrough(AnEnumeration.FOO);"
+ "\n }"
+ "\n "
+ "\n public boolean switchNonDefaultFallThrough(AnEnumeration e) {"
+ "\n switch (e) { // tests assume this is line 170"
+ "\n case FOO:"
+ "\n System.out.println(\"FOO\");"
+ "\n "
+ "\n case BAR:"
+ "\n System.out.println(\"BAR\");"
+ "\n return true;"
+ "\n "
+ "\n case GONK:"
+ "\n return true;"
+ "\n "
+ "\n default:"
+ "\n return false;"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithBoolean() {"
+ "\n switchWithBoolean(1, false);"
+ "\n switchWithBoolean(3, false);"
+ "\n switchWithBoolean(7, true);"
+ "\n switchWithBoolean(7, false);"
+ "\n switchWithBoolean(8, true);"
+ "\n }"
+ "\n "
+ "\n public void switchWithBoolean(int type, boolean aBoolean) {"
+ "\n switch (type) { // tests assume this is line 195"
+ "\n case 9:{"
+ "\n System.out.println(\"9\");"
+ "\n break;"
+ "\n }"
+ "\n case 1:{"
+ "\n try {"
+ "\n System.out.println(\"1\");"
+ "\n } catch (Exception e) {}"
+ "\n break; // tests assume this is line 204"
+ "\n }"
+ "\n case 5:{"
+ "\n System.out.println(\"5\");"
+ "\n break;"
+ "\n }"
+ "\n case 4:{"
+ "\n System.out.println(\"4\");"
+ "\n break;"
+ "\n }"
+ "\n case 3:{"
+ "\n System.out.println(\"3\");"
+ "\n break;"
+ "\n }"
+ "\n case 7:{"
+ "\n if (aBoolean) {"
+ "\n System.out.println(\"7\");"
+ "\n break;"
+ "\n }"
+ "\n // if aBoolean == false, this will fall through to the next case."
+ "\n }"
+ "\n case 8:{"
+ "\n if (aBoolean) {"
+ "\n System.out.println(\"8\");"
+ "\n break;"
+ "\n }"
+ "\n }"
+ "\n }"
+ "\n }"
+ "\n "
+ "\n enum ABCDEnum { A,B,C,D;};"
+ "\n "
+ "\n public void switchWithEnum(ABCDEnum value) {"
+ "\n switch (value) { // tests assume this is line 237"
+ "\n case B: "
+ "\n System.out.println(\"B\");"
+ "\n break;"
+ "\n case C:"
+ "\n System.out.println(\"C\");"
+ "\n case A:"
+ "\n System.out.println(\"A\");"
+ "\n break;"
+ "\n default:"
+ "\n System.out.println(\"default\");"
+ "\n } "
+ "\n }"
+ "\n "
+ "\n public void switchWithAllEnumValues(ABCDEnum value) {"
+ "\n switch (value) { // tests assume this is line 252"
+ "\n case B: "
+ "\n System.out.println(\"B\");"
+ "\n break;"
+ "\n case C:"
+ "\n System.out.println(\"C\");"
+ "\n case A:"
+ "\n System.out.println(\"A\");"
+ "\n break;"
+ "\n case D:"
+ "\n System.out.println(\"D\");"
+ "\n break;"
+ "\n default:"
+ "\n // Not reachable, but compiler does not mark it as dead code."
+ "\n System.out.println(\"default\"); // tests assume this is line 266"
+ "\n } "
+ "\n }"
+ "\n "
+ "\n public void switchWithAllButDefaultEnumValues(ABCDEnum value) {"
+ "\n switch (value) { // tests assume this is line 271 "
+ "\n case B: "
+ "\n System.out.println(\"B\");"
+ "\n break;"
+ "\n case C:"
+ "\n System.out.println(\"C\");"
+ "\n case A:"
+ "\n System.out.println(\"A\");"
+ "\n break;"
+ "\n case D:"
+ "\n System.out.println(\"D\");"
+ "\n break;"
+ "\n } "
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithEnum() {"
+ "\n switchWithEnum(ABCDEnum.B);"
+ "\n switchWithEnum(ABCDEnum.C);"
+ "\n switchWithEnum(ABCDEnum.D);"
+ "\n switchWithEnum(ABCDEnum.B);"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithAllEnumValues() {"
+ "\n switchWithAllEnumValues(ABCDEnum.A);"
+ "\n switchWithAllEnumValues(ABCDEnum.B);"
+ "\n switchWithAllEnumValues(ABCDEnum.C);"
+ "\n switchWithAllEnumValues(ABCDEnum.D);"
+ "\n }"
+ "\n "
+ "\n public void callSwitchWithAllButDefaultEnumValues() {"
+ "\n switchWithAllButDefaultEnumValues(ABCDEnum.A);"
+ "\n switchWithAllButDefaultEnumValues(ABCDEnum.B);"
+ "\n switchWithAllButDefaultEnumValues(ABCDEnum.C);"
+ "\n switchWithAllButDefaultEnumValues(ABCDEnum.D);"
+ "\n }"
+ "\n "
+ "\n "
+ "\n public static void main(String[] args) {"
+ "\n Main main = new Main();"
+ "\n main.callNoDefaultSwitch();"
+ "\n main.callSwitchFallThrough();"
+ "\n main.callSwitchWithDefault();"
+ "\n main.callSwitchWithoutGaps();"
+ "\n main.callSwitchWithoutGapsWithFallThrough();"
+ "\n main.callSwitchBug2075537();"
+ "\n main.callSwitchBug2075537_2();"
+ "\n main.callSwitchNonDefaultFallThrough();"
+ "\n main.callSwitchWithBoolean();"
+ "\n main.callSwitchWithEnum();"
+ "\n main.callSwitchWithAllEnumValues();"
+ "\n main.callSwitchWithAllButDefaultEnumValues();"
+ "\n } " + "\n }");
TestUtils.compileSource(ant, srcDir);
TestUtils.instrumentClasses(ant, srcDir, datafile, instrumentDir);
/*
* Kick off the Main (instrumented) class.
*/
Java java = new Java();
java.setProject(TestUtils.project);
java.setClassname("mypackage.Main");
java.setDir(srcDir);
java.setFork(true);
java.setFailonerror(true);
java.setClasspath(TestUtils.getCoberturaDefaultClasspath());
java.execute();
/*
* Now create a cobertura html report and make sure the files are created.
*/
ReportTask reportTask = new ReportTask();
reportTask.setProject(TestUtils.project);
reportTask.setDataFile(datafile.getAbsolutePath());
reportTask.setFormat("html");
reportTask.setDestDir(reportDir);
reportTask.setSrcDir(srcDir.getAbsolutePath());
reportTask.execute();
assertTrue(new File(reportDir, "index.html").exists());
assertTrue(new File(reportDir, "mypackage.Main.html").exists());
/*
* Now create a cobertura xml file and make sure the correct counts are in it.
*/
reportTask = new ReportTask();
reportTask.setProject(TestUtils.project);
reportTask.setDataFile(datafile.getAbsolutePath());
reportTask.setFormat("xml");
reportTask.setDestDir(srcDir);
reportTask.execute();
Node dom = TestUtils.getXMLReportDOM(srcDir.getAbsolutePath()
+ "/coverage.xml");
//switchWithBoolean
List<Node> lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithBoolean");
assertConditionCoverage(lines, "50% (4/8)", 195);
/*
* A try catch just before a break statement used to cause Cobertura
* to report the line with the break as uncovered. Make sure
* this no longer happens.
*/
// Unhapilly Java compiler is messing the code too much to support the case.
// def breakInSwitchWithBooleanLine = lines.grep {it.number == '204'}[0]
// assertEquals(1, breakInSwitchWithBooleanLine.hits)
//switchNonDefaultFallThrough
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchNonDefaultFallThrough");
assertConditionCoverage(lines, "33% (1/3)", 170);
//switchBug2075537
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchBug2075537");
assertConditionCoverage(lines, "50% (1/2)", 132);
//switchBug2075537_2
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchBug2075537_2");
assertConditionCoverage(lines, "100% (3/3)", 150);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithoutGaps");
assertConditionCoverage(lines, "25% (1/4)", 76);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithoutGapsWithFallThrough");
assertConditionCoverage(lines, "25% (1/4)", 100);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"callNoDefaultSwitch");
assertConditionCoverage(lines, "33% (1/3)", 7);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchFallThrough");
assertConditionCoverage(lines, "33% (1/3)", 23);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithDefault");
assertConditionCoverage(lines, "16% (1/6)", 40);
lines = TestUtils
.getLineCounts(dom, "mypackage.Main", "switchWithEnum");
assertConditionCoverage(lines, "75% (3/4)", 237);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithAllEnumValues");
assertConditionCoverage(lines, "100% (4/4)", 252);
boolean found = false;
for (Node node : lines) {
if (Integer.valueOf((String) node.attribute("number")) == 266) {
found = true;
assertEquals((Integer) 0, Integer.valueOf((String) node
.attribute("hits")));
}
}
assertTrue("Failed to find node on line 266", found);
lines = TestUtils.getLineCounts(dom, "mypackage.Main",
"switchWithAllButDefaultEnumValues");
assertConditionCoverage(lines, "100% (4/4)", 271);
}
}