1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.report.internal.html.table; 13 14 import static org.junit.Assert.assertEquals; 15 import static org.junit.Assert.fail; 16 17 import java.io.IOException; 18 import java.util.Arrays; 19 import java.util.Comparator; 20 import java.util.List; 21 22 import org.jacoco.core.analysis.CounterComparator; 23 import org.jacoco.core.analysis.CoverageNodeImpl; 24 import org.jacoco.core.analysis.ICoverageNode; 25 import org.jacoco.core.analysis.ICoverageNode.CounterEntity; 26 import org.jacoco.core.analysis.ICoverageNode.ElementType; 27 import org.jacoco.core.internal.analysis.CounterImpl; 28 import org.jacoco.report.MemoryMultiReportOutput; 29 import org.jacoco.report.internal.ReportOutputFolder; 30 import org.jacoco.report.internal.html.HTMLDocument; 31 import org.jacoco.report.internal.html.HTMLElement; 32 import org.jacoco.report.internal.html.HTMLSupport; 33 import org.jacoco.report.internal.html.resources.Resources; 34 import org.junit.After; 35 import org.junit.Before; 36 import org.junit.Test; 37 import org.w3c.dom.Document; 38 39 /** 40 * Unit tests for {@link Table}. 41 */ 42 public class TableTest { 43 44 private MemoryMultiReportOutput output; 45 46 private ReportOutputFolder root; 47 48 private Resources resources; 49 50 private HTMLDocument doc; 51 52 private HTMLElement body; 53 54 private Table table; 55 56 @Before 57 public void setup() throws IOException { 58 output = new MemoryMultiReportOutput(); 59 root = new ReportOutputFolder(output); 60 resources = new Resources(root); 61 doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); 62 doc.head().title(); 63 body = doc.body(); 64 table = new Table(); 65 } 66 67 @After 68 public void teardown() throws IOException { 69 output.close(); 70 output.assertAllClosed(); 71 } 72 73 @Test 74 public void testCallbackSequence() throws IOException { 75 final IColumnRenderer recorder = new StubRenderer( 76 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)) { 77 78 private final StringBuilder store = new StringBuilder(); 79 80 @Override 81 public boolean init(List<? extends ITableItem> items, 82 ICoverageNode total) { 83 store.append("init-"); 84 return true; 85 } 86 87 @Override 88 public void footer(HTMLElement td, ICoverageNode total, 89 Resources resources, ReportOutputFolder base) { 90 store.append("footer-"); 91 } 92 93 @Override 94 public void item(HTMLElement td, ITableItem item, 95 Resources resources, ReportOutputFolder base) { 96 store.append("item").append(item.getLinkLabel()).append("-"); 97 } 98 99 @Override 100 public String toString() { 101 return store.toString(); 102 } 103 104 }; 105 final List<ITableItem> items = Arrays.asList(createItem("A", 1), 106 createItem("B", 2), createItem("C", 3)); 107 table.add("Header", null, recorder, false); 108 table.render(body, items, createTotal("Sum", 6), resources, root); 109 doc.close(); 110 assertEquals("init-footer-itemA-itemB-itemC-", recorder.toString()); 111 } 112 113 @Test 114 public void testInvisible() throws IOException { 115 final IColumnRenderer column = new StubRenderer( 116 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)) { 117 118 @Override 119 public boolean init(List<? extends ITableItem> items, 120 ICoverageNode total) { 121 return false; 122 } 123 124 @Override 125 public void footer(HTMLElement td, ICoverageNode total, 126 Resources resources, ReportOutputFolder base) { 127 fail(); 128 } 129 130 @Override 131 public void item(HTMLElement td, ITableItem item, 132 Resources resources, ReportOutputFolder base) { 133 fail(); 134 } 135 }; 136 final List<ITableItem> items = Arrays.asList(createItem("A", 1)); 137 table.add("Header", null, column, false); 138 table.render(body, items, createTotal("Sum", 1), resources, root); 139 doc.close(); 140 } 141 142 @Test(expected = IllegalStateException.class) 143 public void testTwoDefaultSorts() throws IOException { 144 doc.close(); 145 table.add("Header1", null, new StubRenderer( 146 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); 147 table.add("Header2", null, new StubRenderer( 148 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); 149 } 150 151 @Test 152 public void testSortIds() throws Exception { 153 final List<ITableItem> items = Arrays.asList(createItem("C", 3), 154 createItem("E", 4), createItem("A", 1), createItem("D", 2)); 155 table.add("Forward", null, new StubRenderer( 156 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), false); 157 table.add( 158 "Reverse", 159 null, 160 new StubRenderer(CounterComparator.TOTALITEMS.reverse().on( 161 CounterEntity.CLASS)), false); 162 table.render(body, items, createTotal("Sum", 6), resources, root); 163 doc.close(); 164 165 final HTMLSupport support = new HTMLSupport(); 166 final Document doc = support.parse(output.getFile("Test.html")); 167 168 // The elements in Column 1 are sorted in forward order: 169 assertEquals("sortable", 170 support.findStr(doc, "/html/body/table/thead/tr/td[1]/@class")); 171 assertEquals("a", 172 support.findStr(doc, "/html/body/table/thead/tr/td[1]/@id")); 173 assertEquals("a2", 174 support.findStr(doc, "/html/body/table/tbody/tr[1]/td[1]/@id")); 175 assertEquals("a3", 176 support.findStr(doc, "/html/body/table/tbody/tr[2]/td[1]/@id")); 177 assertEquals("a0", 178 support.findStr(doc, "/html/body/table/tbody/tr[3]/td[1]/@id")); 179 assertEquals("a1", 180 support.findStr(doc, "/html/body/table/tbody/tr[4]/td[1]/@id")); 181 182 // The elements in Column 2 are sorted in reverse order: 183 assertEquals("sortable", 184 support.findStr(doc, "/html/body/table/thead/tr/td[2]/@class")); 185 assertEquals("b", 186 support.findStr(doc, "/html/body/table/thead/tr/td[2]/@id")); 187 assertEquals("b1", 188 support.findStr(doc, "/html/body/table/tbody/tr[1]/td[2]/@id")); 189 assertEquals("b0", 190 support.findStr(doc, "/html/body/table/tbody/tr[2]/td[2]/@id")); 191 assertEquals("b3", 192 support.findStr(doc, "/html/body/table/tbody/tr[3]/td[2]/@id")); 193 assertEquals("b2", 194 support.findStr(doc, "/html/body/table/tbody/tr[4]/td[2]/@id")); 195 } 196 197 @Test 198 public void testDefaultSorting() throws Exception { 199 final List<ITableItem> items = Arrays.asList(createItem("C", 3), 200 createItem("E", 5), createItem("A", 1), createItem("D", 4), 201 createItem("B", 2)); 202 table.add("Forward", null, new StubRenderer( 203 CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); 204 table.render(body, items, createTotal("Sum", 1), resources, root); 205 doc.close(); 206 207 final HTMLSupport support = new HTMLSupport(); 208 final Document doc = support.parse(output.getFile("Test.html")); 209 210 assertEquals("down sortable", 211 support.findStr(doc, "/html/body/table/thead/tr/td[1]/@class")); 212 assertEquals("A", 213 support.findStr(doc, "/html/body/table/tbody/tr[1]/td[1]")); 214 assertEquals("B", 215 support.findStr(doc, "/html/body/table/tbody/tr[2]/td[1]")); 216 assertEquals("C", 217 support.findStr(doc, "/html/body/table/tbody/tr[3]/td[1]")); 218 assertEquals("D", 219 support.findStr(doc, "/html/body/table/tbody/tr[4]/td[1]")); 220 assertEquals("E", 221 support.findStr(doc, "/html/body/table/tbody/tr[5]/td[1]")); 222 } 223 224 private ITableItem createItem(final String name, final int count) { 225 final ICoverageNode node = new CoverageNodeImpl(ElementType.GROUP, name) { 226 { 227 this.classCounter = CounterImpl.getInstance(count, 0); 228 } 229 }; 230 return new ITableItem() { 231 public String getLinkLabel() { 232 return name; 233 } 234 235 public String getLink(ReportOutputFolder base) { 236 return name + ".html"; 237 } 238 239 public String getLinkStyle() { 240 return Resources.getElementStyle(node.getElementType()); 241 } 242 243 public ICoverageNode getNode() { 244 return node; 245 } 246 }; 247 } 248 249 private ICoverageNode createTotal(final String name, final int count) { 250 return new CoverageNodeImpl(ElementType.GROUP, name) { 251 { 252 this.classCounter = CounterImpl.getInstance(count, 0); 253 } 254 }; 255 } 256 257 private static class StubRenderer implements IColumnRenderer { 258 259 private final Comparator<ITableItem> comparator; 260 261 StubRenderer(Comparator<ICoverageNode> comparator) { 262 this.comparator = new TableItemComparator(comparator); 263 } 264 265 public boolean init(List<? extends ITableItem> items, 266 ICoverageNode total) { 267 return true; 268 } 269 270 public void footer(HTMLElement td, ICoverageNode total, 271 Resources resources, ReportOutputFolder base) { 272 } 273 274 public void item(HTMLElement td, ITableItem item, Resources resources, 275 ReportOutputFolder base) throws IOException { 276 td.text(item.getLinkLabel()); 277 } 278 279 public Comparator<ITableItem> getComparator() { 280 return comparator; 281 } 282 283 } 284 285 } 286