001/* 002 * Shredzone Commons 003 * 004 * Copyright (C) 2014 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Library General Public License as 009 * published by the Free Software Foundation, either version 3 of the 010 * License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU Library General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package org.shredzone.commons.xml; 021 022import static java.util.Arrays.copyOfRange; 023import static java.util.stream.Collectors.toList; 024import static org.hamcrest.Matchers.*; 025import static org.junit.Assert.assertThat; 026import static org.mockito.Mockito.mock; 027 028import java.util.ArrayList; 029import java.util.List; 030import java.util.Spliterator; 031import java.util.stream.IntStream; 032 033import org.junit.Before; 034import org.junit.Test; 035import org.w3c.dom.Node; 036import org.w3c.dom.NodeList; 037 038/** 039 * Unit tests for the {@link NodeListSpliterator}. 040 * 041 * @author Richard "Shred" Körber 042 */ 043public class NodeListSpliteratorTest { 044 045 private static final int NODES = 11; // prime number, so splitting isn't too easy 046 private static final int HALF = NODES / 2; 047 048 private Node[] nodes; 049 private NodeList nodeList; 050 051 /** 052 * Sets up an array of nodes and a {@link NodeList} returning that array. 053 */ 054 @Before 055 public void init() { 056 nodes = new Node[NODES]; 057 IntStream.range(0, nodes.length).forEach(ix -> nodes[ix] = mock(Node.class)); 058 059 nodeList = new NodeList() { 060 @Override 061 public Node item(int index) { 062 return nodes[index]; 063 } 064 @Override 065 public int getLength() { 066 return nodes.length; 067 } 068 }; 069 } 070 071 /** 072 * Is {@link NodeListSpliterator#characteristics()} returning the correct 073 * characteristics? 074 */ 075 @Test 076 public void characteristicsTest() { 077 NodeListSpliterator spliterator = new NodeListSpliterator(nodeList); 078 assertThat(spliterator.characteristics(), is(Spliterator.ORDERED 079 | Spliterator.DISTINCT | Spliterator.SIZED | Spliterator.NONNULL 080 | Spliterator.SUBSIZED)); 081 } 082 083 /** 084 * Does the {@link NodeListSpliterator#tryAdvance(java.util.function.Consumer)} 085 * return all {@link NodeList} elements, in correct order? 086 */ 087 @Test 088 public void simpleTest() { 089 NodeListSpliterator spliterator = new NodeListSpliterator(nodeList); 090 assertThat(spliterator.estimateSize(), is((long) nodes.length)); 091 092 List<Node> result = consume(spliterator); 093 094 assertThat(result, contains(nodes)); 095 assertThat(spliterator.estimateSize(), is(0L)); 096 } 097 098 /** 099 * Does {@link NodeListSpliterator#trySplit()} split up correctly, leaving two 100 * spliterators containing half of the {@link NodeList} each? 101 */ 102 @Test 103 public void splitTest() { 104 NodeListSpliterator s1 = new NodeListSpliterator(nodeList); 105 assertThat(s1.estimateSize(), is((long) nodes.length)); 106 107 Spliterator<Node> s2 = s1.trySplit(); 108 assertThat(s1.estimateSize(), is((long) HALF)); 109 assertThat(s2.estimateSize(), is((long) (NODES - HALF))); 110 111 List<Node> r1 = consume(s1); 112 assertThat(s1.estimateSize(), is(0L)); 113 assertThat(r1, contains(copyOfRange(nodes, 0, HALF))); 114 115 List<Node> r2 = consume(s2); 116 assertThat(s2.estimateSize(), is(0L)); 117 assertThat(r2, contains(copyOfRange(nodes, HALF, NODES))); 118 } 119 120 /** 121 * Does {@link NodeListSpliterator#trySplit()} split up correctly to the limits? 122 */ 123 @Test 124 public void fullSplitTest() { 125 List<Spliterator<Node>> spliterators = new ArrayList<>(); 126 spliterators.add(new NodeListSpliterator(nodeList)); 127 128 // Split all spliterators until they contain a single element 129 while (spliterators.size() != NODES) { 130 List<Spliterator<Node>> newSpliterators = new ArrayList<>(); 131 for (Spliterator<Node> sp1 : spliterators) { 132 newSpliterators.add(sp1); 133 Spliterator<Node> sp2 = sp1.trySplit(); 134 if (sp2 != null) { 135 newSpliterators.add(sp2); 136 } 137 } 138 spliterators = newSpliterators; 139 } 140 141 // Make sure all spliterators cannot be split any further 142 for (Spliterator<Node> sp : spliterators) { 143 assertThat(sp.estimateSize(), is(1L)); 144 assertThat(sp.trySplit(), is(nullValue())); 145 } 146 147 // Consume the content of each spliterator, make sure they are in correct order 148 for (int ix = 0; ix < NODES; ix++) { 149 Node refNode = nodes[ix]; 150 Spliterator<Node> sp = spliterators.get(ix); 151 sp.tryAdvance(it -> assertThat(it, is(refNode))); 152 assertThat(sp.estimateSize(), is(0L)); 153 } 154 } 155 156 /** 157 * Does the {@link NodeListSpliterator#stream()} method return a stream containing 158 * all remaining elements? 159 */ 160 @Test 161 public void streamTest() { 162 NodeListSpliterator spliterator = new NodeListSpliterator(nodeList); 163 List<Node> result = spliterator.stream().collect(toList()); 164 assertThat(result, contains(nodes)); 165 } 166 167 /** 168 * Consumes the {@link Spliterator} and returns a list of all {@link Node} retrieved. 169 * 170 * @param spliterator 171 * {@link Spliterator} to consume 172 * @return List of all {@link Node} elements of that {@link Spliterator} 173 */ 174 private List<Node> consume(Spliterator<Node> spliterator) { 175 List<Node> result = new ArrayList<>(); 176 spliterator.forEachRemaining(result::add); 177 return result; 178 } 179 180}