• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 636

05 Dec 2025 03:27AM UTC coverage: 80.509%. Remained the same
636

push

github

hazendaz
Cleanup more old since tags

you guessed it, at this point going to jautodoc the rest so the warnings on builds go away ;)

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8249 of 10132 relevant lines covered (81.42%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.49
/src/main/java/com/meterware/httpunit/dom/NodeImpl.java
1
/*
2
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.httpunit.dom;
21

22
import java.util.ArrayList;
23
import java.util.Hashtable;
24
import java.util.Iterator;
25

26
import org.w3c.dom.DOMException;
27
import org.w3c.dom.Document;
28
import org.w3c.dom.Element;
29
import org.w3c.dom.NamedNodeMap;
30
import org.w3c.dom.Node;
31
import org.w3c.dom.NodeList;
32
import org.w3c.dom.UserDataHandler;
33
import org.w3c.dom.html.HTMLIFrameElement;
34

35
public abstract class NodeImpl extends AbstractDomComponent implements Node {
1✔
36

37
    private static final long serialVersionUID = 1L;
38
    private DocumentImpl _ownerDocument;
39
    private NodeImpl _parentNode;
40
    private NodeImpl _firstChild;
41
    private NodeImpl _nextSibling;
42
    private NodeImpl _previousSibling;
43
    private Hashtable _userData = new Hashtable<>();
1✔
44

45
    static IteratorMask SKIP_IFRAMES = subtreeRoot -> subtreeRoot instanceof HTMLIFrameElement;
1✔
46

47
    protected void initialize(DocumentImpl ownerDocument) {
48
        if (_ownerDocument != null) {
1!
49
            throw new IllegalStateException("NodeImpl already initialized");
×
50
        }
51
        if (ownerDocument == null) {
1!
52
            throw new IllegalArgumentException("No owner document specified");
×
53
        }
54
        _ownerDocument = ownerDocument;
1✔
55
    }
1✔
56

57
    // ------------------------------------------ ScriptableObject methods
58
    // --------------------------------------------------
59

60
    // ------------------------------------------ ScriptingEngine methods
61
    // --------------------------------------------------
62

63
    // ----------------------------------------------- Node methods
64
    // ---------------------------------------------------------
65

66
    @Override
67
    public Node getParentNode() {
68
        return _parentNode;
1✔
69
    }
70

71
    @Override
72
    public NodeList getChildNodes() {
73
        ArrayList list = new ArrayList<>();
1✔
74
        for (NodeImpl child = _firstChild; child != null; child = child._nextSibling) {
1✔
75
            list.add(child);
1✔
76
        }
77
        return new NodeListImpl(list);
1✔
78
    }
79

80
    @Override
81
    public Node getFirstChild() {
82
        return _firstChild;
1✔
83
    }
84

85
    @Override
86
    public Node getLastChild() {
87
        if (_firstChild == null) {
1✔
88
            return null;
1✔
89
        }
90

91
        Node child = _firstChild;
1✔
92
        while (child.getNextSibling() != null) {
1✔
93
            child = child.getNextSibling();
1✔
94
        }
95
        return child;
1✔
96
    }
97

98
    @Override
99
    public Node getPreviousSibling() {
100
        return _previousSibling;
1✔
101
    }
102

103
    @Override
104
    public Node getNextSibling() {
105
        return _nextSibling;
1✔
106
    }
107

108
    @Override
109
    public NamedNodeMap getAttributes() {
110
        return null;
1✔
111
    }
112

113
    @Override
114
    public Document getOwnerDocument() {
115
        return _ownerDocument;
1✔
116
    }
117

118
    @Override
119
    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
120
        NodeImpl refChildNode = (NodeImpl) refChild;
1✔
121
        if (refChildNode.getParentNode() != this) {
1✔
122
            throw new DOMException(DOMException.NOT_FOUND_ERR, "Must specify an existing child as the reference");
1✔
123
        }
124
        NodeImpl newChildNode = getChildIfPermitted(newChild);
1✔
125
        removeFromTree(newChildNode);
1✔
126
        newChildNode._parentNode = this;
1✔
127
        if (refChildNode._previousSibling == null) {
1✔
128
            _firstChild = newChildNode;
1✔
129
        } else {
130
            refChildNode._previousSibling.setNextSibling(newChildNode);
1✔
131
        }
132
        newChildNode.setNextSibling(refChildNode);
1✔
133
        return newChildNode;
1✔
134
    }
135

136
    private void removeFromTree(NodeImpl childNode) {
137
        if (childNode._parentNode != null) {
1✔
138
            if (childNode._previousSibling != null) {
1✔
139
                childNode._previousSibling.setNextSibling(childNode._nextSibling);
1✔
140
            } else {
141
                childNode._parentNode._firstChild = childNode._nextSibling;
1✔
142
                childNode._nextSibling._previousSibling = null;
1✔
143
            }
144
            childNode._parentNode = null;
1✔
145
        }
146
    }
1✔
147

148
    @Override
149
    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
150
        insertBefore(newChild, oldChild);
1✔
151
        return removeChild(oldChild);
1✔
152
    }
153

154
    @Override
155
    public Node removeChild(Node oldChild) throws DOMException {
156
        if (oldChild.getParentNode() != this) {
1✔
157
            throw new DOMException(DOMException.NOT_FOUND_ERR, "May only remove a node from its own parent");
1✔
158
        }
159
        removeFromTree((NodeImpl) oldChild);
1✔
160
        return oldChild;
1✔
161
    }
162

163
    @Override
164
    public Node appendChild(Node newChild) throws DOMException {
165
        if (newChild == null) {
1!
166
            throw new IllegalArgumentException("child to append may not be null");
×
167
        }
168

169
        NodeImpl childNode = getChildIfPermitted(newChild);
1✔
170
        removeFromTree(childNode);
1✔
171
        childNode._parentNode = this;
1✔
172
        if (_firstChild == null) {
1✔
173
            _firstChild = childNode;
1✔
174
        } else {
175
            ((NodeImpl) getLastChild()).setNextSibling(childNode);
1✔
176
        }
177
        return newChild;
1✔
178
    }
179

180
    protected NodeImpl getChildIfPermitted(Node proposedChild) {
181
        if (!(proposedChild instanceof NodeImpl)) {
1!
182
            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
×
183
                    "Specified node is from a different DOM implementation");
184
        }
185
        NodeImpl childNode = (NodeImpl) proposedChild;
1✔
186
        if (getOwnerDocument() != childNode._ownerDocument) {
1✔
187
            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "Specified node is from a different document");
1✔
188
        }
189
        for (Node parent = this; parent != null; parent = parent.getParentNode()) {
1✔
190
            if (proposedChild == parent) {
1✔
191
                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "May not add node as its own descendant");
1✔
192
            }
193
        }
194

195
        return childNode;
1✔
196
    }
197

198
    private void setNextSibling(NodeImpl sibling) {
199
        _nextSibling = sibling;
1✔
200
        if (sibling != null) {
1✔
201
            sibling._previousSibling = this;
1✔
202
        }
203
    }
1✔
204

205
    @Override
206
    public boolean hasChildNodes() {
207
        return _firstChild != null;
1✔
208
    }
209

210
    @Override
211
    public Node cloneNode(boolean deep) {
212
        return getOwnerDocument().importNode(this, deep);
1✔
213
    }
214

215
    @Override
216
    public void normalize() {
217
    }
×
218

219
    @Override
220
    public boolean isSupported(String feature, String version) {
221
        return false;
×
222
    }
223

224
    @Override
225
    public String getNamespaceURI() {
226
        return null;
1✔
227
    }
228

229
    @Override
230
    public String getPrefix() {
231
        return null;
×
232
    }
233

234
    @Override
235
    public void setPrefix(String prefix) throws DOMException {
236
    }
×
237

238
    @Override
239
    public String getLocalName() {
240
        return null;
1✔
241
    }
242

243
    @Override
244
    public boolean hasAttributes() {
245
        return false;
×
246
    }
247

248
    // ------------------------------------ DOM level 3 methods
249
    // -------------------------------------------------------------
250

251
    @Override
252
    public Object setUserData(String key, Object data, UserDataHandler handler) {
253
        return _userData.put(key, data);
×
254
    }
255

256
    @Override
257
    public Object getUserData(String key) {
258
        return _userData.get(key);
×
259
    }
260

261
    @Override
262
    public Object getFeature(String feature, String version) {
263
        return null;
×
264
    }
265

266
    @Override
267
    public boolean isEqualNode(Node arg) {
268
        return false; // To change body of implemented methods use File | Settings | File Templates.
×
269
    }
270

271
    @Override
272
    public String lookupNamespaceURI(String prefix) {
273
        return null; // To change body of implemented methods use File | Settings | File Templates.
×
274
    }
275

276
    @Override
277
    public String getBaseURI() {
278
        return null; // To change body of implemented methods use File | Settings | File Templates.
×
279
    }
280

281
    @Override
282
    public short compareDocumentPosition(Node other) throws DOMException {
283
        return 0; // To change body of implemented methods use File | Settings | File Templates.
×
284
    }
285

286
    @Override
287
    public String getTextContent() throws DOMException {
288
        return null; // To change body of implemented methods use File | Settings | File Templates.
×
289
    }
290

291
    @Override
292
    public void setTextContent(String textContent) throws DOMException {
293
        // To change body of implemented methods use File | Settings | File Templates.
294
    }
×
295

296
    @Override
297
    public boolean isSameNode(Node other) {
298
        return this == other;
1✔
299
    }
300

301
    @Override
302
    public String lookupPrefix(String namespaceURI) {
303
        return null; // To change body of implemented methods use File | Settings | File Templates.
×
304
    }
305

306
    @Override
307
    public boolean isDefaultNamespace(String namespaceURI) {
308
        return false; // To change body of implemented methods use File | Settings | File Templates.
×
309
    }
310

311
    // ----------------------------------------- implementation internals
312
    // ---------------------------------------------------
313

314
    public NodeList getElementsByTagName(String name) {
315
        ArrayList matchingElements = new ArrayList<>();
1✔
316
        appendElementsWithTag(name, matchingElements);
1✔
317
        return new NodeListImpl(matchingElements);
1✔
318
    }
319

320
    private void appendElementsWithTag(String name, ArrayList matchingElements) {
321
        for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) {
1✔
322
            if (child.getNodeType() != ELEMENT_NODE) {
1✔
323
                continue;
1✔
324
            }
325
            if (name.equals("*") || ((Element) child).getTagName().equalsIgnoreCase(name)) {
1✔
326
                matchingElements.add(child);
1✔
327
            }
328
            ((NodeImpl) child).appendElementsWithTag(name, matchingElements);
1✔
329
        }
330
    }
1✔
331

332
    protected NodeList getElementsByTagNames(String[] names) {
333
        ArrayList matchingElements = new ArrayList<>();
1✔
334
        appendElementsWithTags(names, matchingElements);
1✔
335
        return new NodeListImpl(matchingElements);
1✔
336
    }
337

338
    void appendElementsWithTags(String[] names, ArrayList matchingElements) {
339
        for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) {
1✔
340
            if (child.getNodeType() != ELEMENT_NODE) {
1✔
341
                continue;
1✔
342
            }
343
            String tagName = ((Element) child).getTagName();
1✔
344
            for (String name : names) {
1✔
345
                if (tagName.equalsIgnoreCase(name)) {
1✔
346
                    matchingElements.add(child);
1✔
347
                }
348
            }
349
            ((NodeImpl) child).appendElementsWithTags(names, matchingElements);
1✔
350
        }
351
    }
1✔
352

353
    String asText() {
354
        StringBuilder sb = new StringBuilder();
1✔
355
        appendContents(sb);
1✔
356
        return sb.toString();
1✔
357
    }
358

359
    void appendContents(StringBuilder sb) {
360
        NodeList nl = getChildNodes();
1✔
361
        for (int i = 0; i < nl.getLength(); i++) {
1✔
362
            ((NodeImpl) nl.item(i)).appendContents(sb);
1✔
363
        }
364
    }
1✔
365

366
    public Iterator preOrderIterator() {
367
        return new PreOrderIterator(this);
1✔
368
    }
369

370
    public Iterator preOrderIterator(IteratorMask mask) {
371
        return new PreOrderIterator(this, mask);
1✔
372
    }
373

374
    public Iterator preOrderIteratorAfterNode() {
375
        return new PreOrderIterator(PreOrderIterator.nextNode(this));
1✔
376
    }
377

378
    /**
379
     * @return
380
     */
381
    public Iterator preOrderIteratorWithinNode() {
382
        PreOrderIterator result = new PreOrderIterator(PreOrderIterator.nextNode(this));
1✔
383
        result.setDoNotLeaveNode(this);
1✔
384
        return result;
1✔
385
    }
386

387
    public Iterator preOrderIteratorWithinNode(IteratorMask mask) {
388
        PreOrderIterator result = new PreOrderIterator(PreOrderIterator.nextNode(this), mask);
1✔
389
        result.setDoNotLeaveNode(this);
1✔
390
        return result;
1✔
391
    }
392

393
    public Iterator preOrderIteratorAfterNode(IteratorMask mask) {
394
        return new PreOrderIterator(PreOrderIterator.nextNode(this), mask);
×
395
    }
396

397
    @Override
398
    protected String getJavaPropertyName(String propertyName) {
399
        if (propertyName.equals("document")) {
1✔
400
            return "ownerDocument";
1✔
401
        }
402
        return propertyName;
1✔
403
    }
404

405
    /**
406
     * allow masking of the iteration
407
     */
408
    interface IteratorMask {
409
        // skip a given subtree
410
        boolean skipSubtree(Node subtreeRoot);
411
    }
412

413
    /**
414
     * iterator for Nodetrees that can be influenced with an Iterator mask to skip specific parts
415
     */
416
    static class PreOrderIterator implements Iterator {
417
        private NodeImpl _nextNode;
418
        private IteratorMask _mask;
419
        private NodeImpl _doNotLeaveNode = null;
1✔
420

421
        /**
422
         * get the limit node
423
         *
424
         * @return
425
         */
426
        public NodeImpl getDoNotLeaveNode() {
427
            return _doNotLeaveNode;
×
428
        }
429

430
        /**
431
         * limit the PreOrderIterator not to leave the given node
432
         *
433
         * @param doNotLeaveNode
434
         */
435
        public void setDoNotLeaveNode(NodeImpl doNotLeaveNode) {
436
            _doNotLeaveNode = doNotLeaveNode;
1✔
437
        }
1✔
438

439
        /**
440
         * check whether the node is a child of the doNotLeaveNode (if one is set)
441
         *
442
         * @param node
443
         *
444
         * @return
445
         */
446
        private boolean isChild(Node node) {
447
            if (node == null) {
1✔
448
                return false;
1✔
449
            }
450
            if (_doNotLeaveNode == null) {
1✔
451
                return true;
1✔
452
            }
453
            Node parent = node.getParentNode();
1✔
454
            if (parent == null) {
1✔
455
                return false;
1✔
456
            }
457
            if (parent.isSameNode(_doNotLeaveNode)) {
1✔
458
                return true;
1✔
459
            }
460
            return isChild(parent);
1✔
461
        }
462

463
        /**
464
         * create a PreOrderIterator starting at a given currentNode
465
         *
466
         * @param currentNode
467
         */
468
        PreOrderIterator(NodeImpl currentNode) {
1✔
469
            _nextNode = currentNode;
1✔
470
        }
1✔
471

472
        /**
473
         * create a PreOrderIterator starting at a given currentNode and setting the iterator mask to the given mask
474
         *
475
         * @param currentNode
476
         * @param mask
477
         */
478
        PreOrderIterator(NodeImpl currentNode, IteratorMask mask) {
479
            this(currentNode);
1✔
480
            _mask = mask;
1✔
481
        }
1✔
482

483
        /**
484
         * is there still a next node?
485
         */
486
        @Override
487
        public boolean hasNext() {
488
            return null != _nextNode;
1✔
489
        }
490

491
        /**
492
         * move one step in the tree
493
         */
494
        @Override
495
        public Object next() {
496
            NodeImpl currentNode = _nextNode;
1✔
497
            _nextNode = nextNode(_nextNode);
1✔
498
            while (_mask != null && _nextNode != null && _mask.skipSubtree(_nextNode)) {
1✔
499
                _nextNode = nextSubtree(_nextNode);
1✔
500
            }
501
            // check that we fit the doNotLeaveNode condition in case there is one
502
            if (!isChild(_nextNode)) {
1✔
503
                _nextNode = null;
1✔
504
            }
505
            return currentNode;
1✔
506
        }
507

508
        @Override
509
        public void remove() {
510
            throw new java.lang.UnsupportedOperationException();
×
511
        }
512

513
        static NodeImpl nextNode(NodeImpl node) {
514
            if (node._firstChild != null) {
1✔
515
                return node._firstChild;
1✔
516
            }
517
            return nextSubtree(node);
1✔
518
        }
519

520
        private static NodeImpl nextSubtree(NodeImpl node) {
521
            if (node._nextSibling != null) {
1✔
522
                return node._nextSibling;
1✔
523
            }
524
            while (node._parentNode != null) {
1✔
525
                node = node._parentNode;
1✔
526
                if (node._nextSibling != null) {
1✔
527
                    return node._nextSibling;
1✔
528
                }
529
            }
530
            return null;
1✔
531
        }
532
    }
533

534
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc