1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
11 // checkTreeConsistency checks that a node and its descendants are all
12 // consistent in their parent/child/sibling relationships.
13 func checkTreeConsistency(n
*Node
) error
{
14 return checkTreeConsistency1(n
, 0)
17 func checkTreeConsistency1(n
*Node
, depth
int) error
{
19 return fmt
.Errorf("html: tree looks like it contains a cycle")
21 if err
:= checkNodeConsistency(n
); err
!= nil {
24 for c
:= n
.FirstChild
; c
!= nil; c
= c
.NextSibling
{
25 if err
:= checkTreeConsistency1(c
, depth
+1); err
!= nil {
32 // checkNodeConsistency checks that a node's parent/child/sibling relationships
34 func checkNodeConsistency(n
*Node
) error
{
40 for p
:= n
.Parent
; p
!= nil; p
= p
.Parent
{
43 return fmt
.Errorf("html: parent list looks like an infinite loop")
48 for c
:= n
.FirstChild
; c
!= nil; c
= c
.NextSibling
{
51 return fmt
.Errorf("html: forward list of children looks like an infinite loop")
54 return fmt
.Errorf("html: inconsistent child/parent relationship")
59 for c
:= n
.LastChild
; c
!= nil; c
= c
.PrevSibling
{
62 return fmt
.Errorf("html: backward list of children looks like an infinite loop")
65 return fmt
.Errorf("html: inconsistent child/parent relationship")
71 return fmt
.Errorf("html: inconsistent parent relationship")
73 if n
.Parent
== n
.FirstChild
{
74 return fmt
.Errorf("html: inconsistent parent/first relationship")
76 if n
.Parent
== n
.LastChild
{
77 return fmt
.Errorf("html: inconsistent parent/last relationship")
79 if n
.Parent
== n
.PrevSibling
{
80 return fmt
.Errorf("html: inconsistent parent/prev relationship")
82 if n
.Parent
== n
.NextSibling
{
83 return fmt
.Errorf("html: inconsistent parent/next relationship")
86 parentHasNAsAChild
:= false
87 for c
:= n
.Parent
.FirstChild
; c
!= nil; c
= c
.NextSibling
{
89 parentHasNAsAChild
= true
93 if !parentHasNAsAChild
{
94 return fmt
.Errorf("html: inconsistent parent/child relationship")
98 if n
.PrevSibling
!= nil && n
.PrevSibling
.NextSibling
!= n
{
99 return fmt
.Errorf("html: inconsistent prev/next relationship")
101 if n
.NextSibling
!= nil && n
.NextSibling
.PrevSibling
!= n
{
102 return fmt
.Errorf("html: inconsistent next/prev relationship")
105 if (n
.FirstChild
== nil) != (n
.LastChild
== nil) {
106 return fmt
.Errorf("html: inconsistent first/last relationship")
108 if n
.FirstChild
!= nil && n
.FirstChild
== n
.LastChild
{
109 // We have a sole child.
110 if n
.FirstChild
.PrevSibling
!= nil || n
.FirstChild
.NextSibling
!= nil {
111 return fmt
.Errorf("html: inconsistent sole child's sibling relationship")
115 seen
:= map[*Node
]bool{}
118 for c
:= n
.FirstChild
; c
!= nil; c
= c
.NextSibling
{
120 return fmt
.Errorf("html: inconsistent repeated child")
125 if last
!= n
.LastChild
{
126 return fmt
.Errorf("html: inconsistent last relationship")
130 for c
:= n
.LastChild
; c
!= nil; c
= c
.PrevSibling
{
132 return fmt
.Errorf("html: inconsistent missing child")
137 if first
!= n
.FirstChild
{
138 return fmt
.Errorf("html: inconsistent first relationship")
142 return fmt
.Errorf("html: inconsistent forwards/backwards child list")