Codebase list xmlunit / 47a7ab4
Merge tag 'upstream/1.6' Upstream version 1.6 Emmanuel Bourg 8 years ago
156 changed file(s) with 31693 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
+584
-0
KEYS less more
0 This file contains the PGP keys of various developers.
1
2 Users: pgp < KEYS
3 gpg --import KEYS
4 Developers:
5 pgp -kxa <your name> and append it to this file.
6 (pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
7 (gpg --list-sigs <your name>
8 && gpg --armor --export <your name>) >> this file.
9
10 pub 1024D/5F6B8B72 2001-05-28
11 uid Stefan Bodewig <bodewig@apache.org>
12 sig 3 5F6B8B72 2001-05-28 Stefan Bodewig <bodewig@apache.org>
13 sig 51898504 2002-01-11 Conor MacNeill <conor@codefeed.com>
14 sig 3 F88341D9 2003-03-17 Lars Eilebrecht <lars@eilebrecht.org>
15 sig 3 2261D073 2003-03-17 Astrid Kessler (Kess) <kess@kess-net.de>
16 sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
17 sig 75A67692 2003-03-18 Erik Abele <erik@codefaktor.de>
18 sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE <pgpCA@ct.heise.de>
19 sig 3 8103A37E 2003-04-04 Andre Malo <nd@apache.org>
20 sig 3 5F6B8B72 2001-05-28 Stefan Bodewig <bodewig@apache.org>
21 sig D6298F01 2003-04-27 Paulo Henrique Gaspar Jorge <pjorge@asatnet.com.br>
22 sig 0CAA68B4 2004-11-11 Patrick Rentsch <patrick.rentsch@suissimage.ch>
23 sig 2FE28BCF 2005-07-01 Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
24 sig 5793498F 2005-07-21 Tim Ellison <tim@ellison.name>
25 sig E4136392 2005-07-21 Noel J. Bergman <noel@apache.org>
26 sig 8408F755 2005-07-21 Christian Geisert <chrisg@apache.org>
27 sig 2 FC243F3C 2005-07-20 Henk P. Penning <penning@cs.uu.nl>
28 sig 3 EC140B81 2005-07-20 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
29 sig 3 EE65E321 2005-07-20 Martin Kraemer <martin@apache.org>
30 sig 3 A99F75DD 2005-07-21 Rodent of Unusual Size <Ken@Coar.Org>
31 sig 3 3642CB4B 2005-07-20 Martin Kraemer <martin@apache.org>
32 sig 3 302DA568 2005-07-21 Rodent of Unusual Size (DSA) <Ken@Coar.Org>
33 sig 3 2C312D2F 2005-07-21 Rodent of Unusual Size (DSS) <Ken@Coar.Org>
34 sig 3 CC78C893 2005-07-22 Rich Bowen <rbowen@rcbowen.com>
35 sig 3 E2D774DF 2005-07-22 Sylvain Wallez <sylvain@apache.org>
36 sig 3 E04F9A89 2005-07-22 Roy T. Fielding <fielding@gbiv.com>
37 sig 3 015AFC8A 2005-07-22 Bertrand Delacretaz <bdelacretaz@apache.org>
38 sig 3 87315C31 2005-07-23 Raphaël Luta <raphael.luta@aptiwan.com>
39 sig 3 E41EDC7E 2005-07-24 Carsten Ziegeler <cziegeler@apache.org>
40 sig 3 F39B3750 2005-07-24 Colm MacCarthaigh <colm@allcosts.net>
41 sig 1CD4861F 2005-07-25 Eran Chinthaka (IU Email) <echintha@indiana.edu>
42 sig EA1BA38D 2005-07-25 Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
43 sig 333E4E84 2005-07-26 Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
44 sig 152924AF 2005-07-29 Sander Temme <sander@temme.net>
45 sig 3 9C85222B 2005-07-24 Henning Schmiedehausen <hps@intermeta.de>
46 sig 3 9978AF86 2005-07-25 Christoph Probst <chris@netzpunkt.org>
47 sig 3 2A623F72 2005-07-25 Christoph Probst <chris@netzpunkt.org>
48 sig 3 F8EA2967 2005-07-26 Brian McCallister <brianm@apache.org>
49 sig 3 C152431A 2005-07-27 Steve Loughran <stevel@apache.org>
50 sig DE885DD3 2005-11-25 Sander Striker <striker@apache.org>
51 sig CE419C8F 2007-01-05 Upayavira <upayavira@odoko.co.uk>
52 sig E222DE4F 2007-05-02 Mathias Herberts <Mathias.Herberts@iroise.net>
53 sig 911203E4 2007-05-02 Mathias Herberts <Mathias.Herberts@gicm.fr>
54 sig F12F6072 2007-05-05 Fred Vos <fred.vos@gmail.com>
55 sig 3 990ED4AA 2007-05-02 Knut Anders Hatlen <kahatlen@apache.org>
56 sig 3 311A3DE5 2007-05-05 Ruediger Pluem <rpluem@apache.org>
57 sig 3 88817402 2007-05-06 Thomas Vandahl <thomas@vandahl.org>
58 sig 5F298824 2007-05-06 Simon Pepping <spepping@leverkruid.eu>
59 sig 4CEED75F 2007-05-06 Nick Burch <nick@gagravarr.org>
60 sig 4358C584 2007-05-06 Vincent Hennebert <vhennebert@apache.org>
61 sig 0B7E6CFA 2007-05-06 Sami Siren <siren@apache.org>
62 sig 3 01530235 2007-05-02 Luc Maisonobe (general purpose) <Luc.Maisonobe@free.fr>
63 sig 40581837 2007-05-08 Nick Kew <nicholas.kew@sun.com>
64 sig 6BD872A0 2007-05-17 Michael Busch (Lucene Committer) <buschmi@apache.org>
65 sig 6210BFC0 2007-05-17 Jean-Frederic Clere <jfclere@apache.org>
66 sig 0F143BC1 2007-05-22 Matt Hogstrom <matt@hogstrom.org>
67 sig A46C4CA1 2007-05-22 Matt Hogstrom <hogstrom@apache.org>
68 sig D1AAEA60 2007-05-31 Reinhard Poetz <reinhard.poetz@gmx.net>
69 sig 084C9113 2007-07-24 Brett Porter <brett@apache.org>
70 sig AF5EC452 2007-07-30 Dennis Lundberg (CODE SIGNING KEY) <dennisl@apache.org>
71 sig C3110611 2008-02-23 Petar Tahchiev <paranoiabla@gmail.com>
72 sig 51047D66 2009-03-25 Tony Stevenson <pctony@apache.org>
73 sig 6A017B17 2009-03-29 H.-Dirk Schmitt <dirk@computer42.org>
74 sig 3B7C75B1 2009-03-31 Gilles Scokart (at apache) <gscokart@apache.org>
75 uid Stefan Bodewig <stefan.bodewig@freenet.de>
76 sig 3 5F6B8B72 2003-03-07 Stefan Bodewig <bodewig@apache.org>
77 sig 3 F88341D9 2003-03-17 Lars Eilebrecht <lars@eilebrecht.org>
78 sig 3 2261D073 2003-03-17 Astrid Kessler (Kess) <kess@kess-net.de>
79 sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
80 sig 75A67692 2003-03-18 Erik Abele <erik@codefaktor.de>
81 sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE <pgpCA@ct.heise.de>
82 sig 3 8103A37E 2003-04-04 Andre Malo <nd@apache.org>
83 sig 51898504 2005-06-21 Conor MacNeill <conor@codefeed.com>
84 sig 0CAA68B4 2004-11-11 Patrick Rentsch <patrick.rentsch@suissimage.ch>
85 sig 2FE28BCF 2005-07-01 Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
86 sig 5793498F 2005-07-21 Tim Ellison <tim@ellison.name>
87 sig 8408F755 2005-07-21 Christian Geisert <chrisg@apache.org>
88 sig 3 EC140B81 2005-07-20 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
89 sig 3 EE65E321 2005-07-20 Martin Kraemer <martin@apache.org>
90 sig 3 A99F75DD 2005-07-21 Rodent of Unusual Size <Ken@Coar.Org>
91 sig 3 3642CB4B 2005-07-20 Martin Kraemer <martin@apache.org>
92 sig 3 302DA568 2005-07-21 Rodent of Unusual Size (DSA) <Ken@Coar.Org>
93 sig 3 2C312D2F 2005-07-21 Rodent of Unusual Size (DSS) <Ken@Coar.Org>
94 sig 3 CC78C893 2005-07-22 Rich Bowen <rbowen@rcbowen.com>
95 sig 3 E2D774DF 2005-07-22 Sylvain Wallez <sylvain@apache.org>
96 sig 3 E04F9A89 2005-07-22 Roy T. Fielding <fielding@gbiv.com>
97 sig 3 87315C31 2005-07-23 Raphaël Luta <raphael.luta@aptiwan.com>
98 sig 3 E41EDC7E 2005-07-24 Carsten Ziegeler <cziegeler@apache.org>
99 sig 3 F39B3750 2005-07-24 Colm MacCarthaigh <colm@allcosts.net>
100 sig 1CD4861F 2005-07-25 Eran Chinthaka (IU Email) <echintha@indiana.edu>
101 sig EA1BA38D 2005-07-25 Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
102 sig 333E4E84 2005-07-26 Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
103 sig 152924AF 2005-07-29 Sander Temme <sander@temme.net>
104 sig 3 9C85222B 2005-07-24 Henning Schmiedehausen <hps@intermeta.de>
105 sig 3 9978AF86 2005-07-25 Christoph Probst <chris@netzpunkt.org>
106 sig 3 2A623F72 2005-07-25 Christoph Probst <chris@netzpunkt.org>
107 sig 3 F8EA2967 2005-07-26 Brian McCallister <brianm@apache.org>
108 sig 3 C152431A 2005-07-27 Steve Loughran <stevel@apache.org>
109 sig DE885DD3 2005-11-25 Sander Striker <striker@apache.org>
110 sig E222DE4F 2007-05-02 Mathias Herberts <Mathias.Herberts@iroise.net>
111 sig 911203E4 2007-05-02 Mathias Herberts <Mathias.Herberts@gicm.fr>
112 sig F12F6072 2007-05-05 Fred Vos <fred.vos@gmail.com>
113 sig 3 990ED4AA 2007-05-02 Knut Anders Hatlen <kahatlen@apache.org>
114 sig 3 311A3DE5 2007-05-05 Ruediger Pluem <rpluem@apache.org>
115 sig 3 88817402 2007-05-06 Thomas Vandahl <thomas@vandahl.org>
116 sig 4CEED75F 2007-05-06 Nick Burch <nick@gagravarr.org>
117 sig 4358C584 2007-05-06 Vincent Hennebert <vhennebert@apache.org>
118 sig 0B7E6CFA 2007-05-06 Sami Siren <siren@apache.org>
119 sig 3 DE8884A0 2007-05-07 Xavier Hanin <xavier.hanin@gmail.com>
120 sig 3 01530235 2007-05-02 Luc Maisonobe (general purpose) <Luc.Maisonobe@free.fr>
121 sig 40581837 2007-05-08 Nick Kew <nicholas.kew@sun.com>
122 sig 6BD872A0 2007-05-17 Michael Busch (Lucene Committer) <buschmi@apache.org>
123 sig 6210BFC0 2007-05-17 Jean-Frederic Clere <jfclere@apache.org>
124 sig 0F143BC1 2007-05-22 Matt Hogstrom <matt@hogstrom.org>
125 sig A46C4CA1 2007-05-22 Matt Hogstrom <hogstrom@apache.org>
126 sig D1AAEA60 2007-05-31 Reinhard Poetz <reinhard.poetz@gmx.net>
127 sig 084C9113 2007-07-24 Brett Porter <brett@apache.org>
128 sig AF5EC452 2007-07-30 Dennis Lundberg (CODE SIGNING KEY) <dennisl@apache.org>
129 sig C3110611 2008-02-23 Petar Tahchiev <paranoiabla@gmail.com>
130 sig 51047D66 2009-03-25 Tony Stevenson <pctony@apache.org>
131 uid Stefan Bodewig <stefan@samaflost.de>
132 sig 3 5F6B8B72 2005-05-31 Stefan Bodewig <bodewig@apache.org>
133 sig 51898504 2005-06-21 Conor MacNeill <conor@codefeed.com>
134 sig 2FE28BCF 2005-07-01 Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
135 sig 5793498F 2005-07-21 Tim Ellison <tim@ellison.name>
136 sig 3 EC140B81 2005-07-20 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
137 sig 3 EE65E321 2005-07-20 Martin Kraemer <martin@apache.org>
138 sig 3 A99F75DD 2005-07-21 Rodent of Unusual Size <Ken@Coar.Org>
139 sig 3 21D0A71B 2005-07-20 Dirk-Willem van Gulik (Chief Internet Architect, role) <dirk-willem.van.gulik@bbc.co.uk>
140 sig 3 3642CB4B 2005-07-20 Martin Kraemer <martin@apache.org>
141 sig 3 302DA568 2005-07-21 Rodent of Unusual Size (DSA) <Ken@Coar.Org>
142 sig 3 2C312D2F 2005-07-21 Rodent of Unusual Size (DSS) <Ken@Coar.Org>
143 sig 3 CC78C893 2005-07-22 Rich Bowen <rbowen@rcbowen.com>
144 sig 3 E2D774DF 2005-07-22 Sylvain Wallez <sylvain@apache.org>
145 sig 3 E04F9A89 2005-07-22 Roy T. Fielding <fielding@gbiv.com>
146 sig 3 87315C31 2005-07-23 Raphaël Luta <raphael.luta@aptiwan.com>
147 sig 3 E41EDC7E 2005-07-24 Carsten Ziegeler <cziegeler@apache.org>
148 sig 3 F39B3750 2005-07-24 Colm MacCarthaigh <colm@allcosts.net>
149 sig 1CD4861F 2005-07-25 Eran Chinthaka (IU Email) <echintha@indiana.edu>
150 sig EA1BA38D 2005-07-25 Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
151 sig 333E4E84 2005-07-26 Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
152 sig 152924AF 2005-07-29 Sander Temme <sander@temme.net>
153 sig 3 9C85222B 2005-07-24 Henning Schmiedehausen <hps@intermeta.de>
154 sig 3 9978AF86 2005-07-25 Christoph Probst <chris@netzpunkt.org>
155 sig 3 2A623F72 2005-07-25 Christoph Probst <chris@netzpunkt.org>
156 sig 3 F8EA2967 2005-07-26 Brian McCallister <brianm@apache.org>
157 sig 3 C152431A 2005-07-27 Steve Loughran <stevel@apache.org>
158 sig DE885DD3 2005-11-25 Sander Striker <striker@apache.org>
159 sig E222DE4F 2007-05-02 Mathias Herberts <Mathias.Herberts@iroise.net>
160 sig 911203E4 2007-05-02 Mathias Herberts <Mathias.Herberts@gicm.fr>
161 sig F12F6072 2007-05-05 Fred Vos <fred.vos@gmail.com>
162 sig 3 990ED4AA 2007-05-02 Knut Anders Hatlen <kahatlen@apache.org>
163 sig 3 311A3DE5 2007-05-05 Ruediger Pluem <rpluem@apache.org>
164 sig 3 88817402 2007-05-06 Thomas Vandahl <thomas@vandahl.org>
165 sig 4CEED75F 2007-05-06 Nick Burch <nick@gagravarr.org>
166 sig 4358C584 2007-05-06 Vincent Hennebert <vhennebert@apache.org>
167 sig 0B7E6CFA 2007-05-06 Sami Siren <siren@apache.org>
168 sig 3 01530235 2007-05-02 Luc Maisonobe (general purpose) <Luc.Maisonobe@free.fr>
169 sig 40581837 2007-05-08 Nick Kew <nicholas.kew@sun.com>
170 sig 6BD872A0 2007-05-17 Michael Busch (Lucene Committer) <buschmi@apache.org>
171 sig 6210BFC0 2007-05-17 Jean-Frederic Clere <jfclere@apache.org>
172 sig 0F143BC1 2007-05-22 Matt Hogstrom <matt@hogstrom.org>
173 sig A46C4CA1 2007-05-22 Matt Hogstrom <hogstrom@apache.org>
174 sig D1AAEA60 2007-05-31 Reinhard Poetz <reinhard.poetz@gmx.net>
175 sig 084C9113 2007-07-24 Brett Porter <brett@apache.org>
176 sig AF5EC452 2007-07-30 Dennis Lundberg (CODE SIGNING KEY) <dennisl@apache.org>
177 sig C3110611 2008-02-23 Petar Tahchiev <paranoiabla@gmail.com>
178 sig 51047D66 2009-03-25 Tony Stevenson <pctony@apache.org>
179 sub 1024g/24774157 2001-05-28
180 sig 5F6B8B72 2001-05-28 Stefan Bodewig <bodewig@apache.org>
181
182 -----BEGIN PGP PUBLIC KEY BLOCK-----
183 Version: GnuPG v1.4.2 (GNU/Linux)
184
185 mQGiBDsSIk4RBADSCj6rUjV64tYCGT1DYKYR7GthyWpNdGHSYLbETBcDatAe1dzQ
186 5NsCgfrlybfyeY+y1lxr3T9bqf6zJWDw/718wff96qmmv1qzexSYtmIrj+h53V82
187 EXwWOFuYMJisuxdT940iQzosm3GOv4MJdEg3oI2SgfEyRQQ6vO4Ob5rHDwCg5taZ
188 nrHOrXx2dIGHxpxRZ0SUl30D/jmtttFjYOQ3LBMriikz5mh2sK3ZnoSRF4o5O0zW
189 Ve6e2SFXOEjVjImKsH6KCbdQNelrAdgiyOoXClyQKsQ27pncbdWo6bO0E3POJZVm
190 XaeW7iudHVr63rU5PViXObIQrdQl0D59j5brKj4vdlTyUw8kaHPvbKPDEOwvZq4Y
191 LJQ5BACA1YilTeXRJqwFsNlpcxCHwlULD4QUVP496prQWf1B7Z6g0KvLGrQsO0Vn
192 Jcn+fEqukysTJixSXCPebosltd4RalJIupVYkp4w6MJ7biaDAlLuNhDcI/AiXTmV
193 dXUedVXIaM8I3Ne23gucwbAyc0Hvb+3cSAKRhl/azFQhuHBvlrQjU3RlZmFuIEJv
194 ZGV3aWcgPGJvZGV3aWdAYXBhY2hlLm9yZz6IYgQTEQIAGgULBwoDBAMVAwIDFgIB
195 AheAAhkBBQI7EiJPABIHZUdQRwABAQkQohFa4V9ri3KPOACfdr6cV41veYBlBHiV
196 FxfLcX7x5OEAniK4u3g2jpNQH3E0ROubdj/RO+RTiEYEEBECAAYFAjw+1Y8ACgkQ
197 gQRkT1GJhQSdkgCeM6RDHUF/E334TtiLPgw7GpmNJSkAoNCLQCW/9VHrV+ZHsodn
198 XUnaD4dIiJkEEwECAAYFAj513wwACgkQPo+38viDQdknZAPlHNiMnR+LUavo2yOY
199 iJT+W9+8+qNs2grYDZ+WSYujaWT2NJrUCYXQRM6gKDyFlkcJvHI9lF2yYMkVetll
200 ZVN1TJkeEdtbHncNHcdq+ZUQR0NkFKTF9d1K7UI2rfWxt1y6a13TcUjpJXzbtw/O
201 XX9EZSI6QQt4rSFlvci9J3mIRgQTEQIABgUCPnXawQAKCRDu0eo5ImHQc0W4AJ9v
202 uq4wlkc6TmmmZPF/gZVLluHcTgCeItrnvzyS11xkIETk6v4b7K4gaiiIPwMFED51
203 qhr9b4jGIdCnGxECRAUAoOaVZW5CdZ9oYr3PwI/i8RJN+JfJAKCmd/XIlYOCpa9Q
204 c4C855pM8NFw6YhGBBARAgAGBQI+d6QQAAoJEBU/oM11pnaSL+sAn1DTHmbhITeE
205 w0ZSgyBLQw2ZhcM5AJ0ZrRBbZ9lbgHXBKOJQiLpWBj4XsYhGBBARAgAGBQI+yi6W
206 AAoJENvSRfyzsqEsF/AAoNXq7Cp/0AwEmWvhoTjmtY6eVYB5AKCMFhBUdYWNXVya
207 lPTq8ThswNUnr4hGBBMRAgAGBQI+jc4sAAoJEMppOXSBA6N+kUoAn1Nj6YqarQg0
208 sL2KrFsQROM3A6fSAKCyl40SpfVJSO33fYuPci9dHp+QCIhXBBMRAgAXBQI7EiJO
209 BQsHCgMEAxUDAgMWAgECF4AACgkQohFa4V9ri3IsngCfbIpJDWj6UgXY7rBH8To1
210 2BgB+RIAn3jw72WJzplAtShVTmuMlRFS+FUNiEYEEBECAAYFAj6sazwACgkQqywx
211 6dYpjwFkeQCeOkJrnO5r2hWDhX4ACPPLObZvXLIAnR0VHAgkEH1W/t7B4zdDYdBB
212 Zrd5iEYEEBECAAYFAkGS8mMACgkQ5BNhMwyqaLQs9ACgio5zJcieYLppigvSYLBf
213 ubUVrXUAnRKZJ6MACpH6fpoz2vkc2dh69tbSiEYEEBECAAYFAkLFMoEACgkQm/Ij
214 RS/ii88aCQCfd1cIawDqpkYU86f3JEjcN85ntFcAni0m8WR6s+bkh3fd+EIrSRsr
215 u3uQiEYEEBECAAYFAkLfRQIACgkQQeoJoFeTSY8XxQCdFd+XEWqyDkCx37gaIQAG
216 4dHpwiUAoOZ/K5OHyTJCNFaBUDtpCh7hL8TPiEYEEBECAAYFAkLfkncACgkQAQVm
217 vOQTY5L3SgCgiEi5/1vYvJrKoAdl0hRWU57ieUIAn2n08BQfMZJQ439aNW/CnIK8
218 jPBPiEYEEBECAAYFAkLgNdAACgkQc84u+4QI91XdNQCgoBB1ebohIflinAPlvI37
219 pFHuu0MAoJ4yMtbKZMaq0xIBnxV9c5uu99tGiEYEEhECAAYFAkLerWMACgkQi5Yp
220 Q/wkPzxD7ACgqKnyeb/fjVS8vov4FePxeLju4msAn1SCGaiF9gEf+qIaZUnjcT7J
221 DJ96iJwEEwECAAYFAkLerG8ACgkQMaY9luwUC4Ea9gP/WON+0xIWOvWP7mKkg/+X
222 0ukW+mbjE426qKtG/B0vNrTKpElmz8ttR+oajqbg20LazoEUuA9ZXjLPfsdWA+vF
223 kxgV6qIdtxYPMamPm7ytEBOmgMowYXUftGteqM5fxLlceHiwdUlynG2fmtMqvPnd
224 2OCezSFRx3W6nvAiIjoLZpCInAQTAQIABgUCQt7H0wAKCRA34/Rf7mXjIcAUA/4n
225 DlQbnToSSDOZkFj1CoGL8TjsVgzrO3r3S3x38uQQTFAE/AGBY4mtHgNcYmiJaC2h
226 N1Y+mlEGu/80Rjv185ZfJsFEerU6Y/9tRJJ1So9AAe5AmvGpD9ysXae5geB+k+ep
227 IMSuf9WMeTRUCbQs9ufGZLV5a8jqstv+btcrzNaY9oicBBMBAgAGBQJC32x4AAoJ
228 EJrNPMCpn3XdRBkD/iNi0Y6A3afDG9ZL/K4JrOPgHUFWC/DgAEBme4AY62agUsT0
229 uXlz+Mu1Ps2E0t26ejScuVMMvqpXg7iJ2+3yKzsnX0ySEXW6/696XEpe3TFn1iVO
230 mMElPKxakn3t/jr6SDepo9jqD5P5CJR4GsDsG3iKIisWdDf81ZXpf86y7A5eiEYE
231 ExECAAYFAkLeuuUACgkQMsnkzjZCy0vmSQCdHGC6jOEVo96yyospTq7bL+EEeioA
232 oNMKIZy5qFLXXZbSNvsj7mDRg2c8iEYEExECAAYFAkLfbHoACgkQUI6uxTAtpWhY
233 hQCaAvqVBsTX5s4c+sTOo06BNMdzHIUAoIwpThAKq936Szy/3Gfv8K3gs5NOiEYE
234 ExECAAYFAkLfbHwACgkQ3bpkuiwxLS9z8ACfYeocOK4J204xwbXgEdUJQyvHK2UA
235 oKz2AF1I2b8Ebu7vTUZLNFV1QMtwiEYEExECAAYFAkLgyTgACgkQXP03+sx4yJNb
236 EgCfRcj6QKHVHQtYVXdCYKUbrj97wAoAnimqV15cvz1siDjUK9K/aTskGwajiEYE
237 ExECAAYFAkLg7MsACgkQybWm7OLXdN8UoQCdFfqef8My1xhn6mLd9WTLLaIewTQA
238 nRXGh/Af4hVG0KwtZcJEA464nCoJiEYEExECAAYFAkLg7TwACgkQW5aAEOBPmol+
239 JwCeLxZjKNisjgP4AxV5BCKR+5SU9NoAoIwPF/7B2NmGNR0t3EZze8wpNhQ0iEYE
240 ExECAAYFAkLg7V8ACgkQN/aP9QFa/IqerACfafKJi4s8LYV2JxNfQKHgmRXzeIIA
241 oNBHOzukDCdxIvmYJfamItnCP45giEYEExECAAYFAkLiYm8ACgkQbZiNF4cxXDH8
242 HwCgq8P29CwMX7PKhRmY3T32APsOaMEAnjdd/WvzVBFtTcJFWkH6iF4L8EQpiEYE
243 ExECAAYFAkLjVb4ACgkQEy5J1OQe3H56DACcDPfWLO5cDkeKFCvIP8mc4p4KkfkA
244 oJITROldIRxXqUiML1oTJxieuHJfiEYEExECAAYFAkLjZNoACgkQdcqio/ObN1CI
245 tACgsJhqBxeZTaSrRVNk3aj6ciAJrgEAoIxPXYTvIpnWBr4/WMbN0jpV0TGEiEYE
246 EBECAAYFAkLkbxIACgkQjON2uBzUhh/gZQCbBpIqkCEuIbd6tqChz3PzcIGiZbgA
247 njluBFHl4l1/NHtP9fEYCgl8nbCviEYEEBECAAYFAkLkkr4ACgkQBJE0Quobo42f
248 +QCgjtO6EOdDRiruCi6gKvwM1a2eRwcAn0XUELm5AZezL5E0rEfIM2FBiMi5iEYE
249 EBECAAYFAkLlwh0ACgkQYRlqLjM+ToS9pwCfUEgO834XY/clWzkw/VLBfe7MLZQA
250 mwdz0nleOHYWFBrnYgEz53d4MxUPiEYEEBECAAYFAkLqY/QACgkQsr68QBUpJK/o
251 MQCfc7M9KpApCWW7eE22PlLoN1sPK+4AoJdwE8TsDM2Pmehk9K+uHIx6FoRviEYE
252 ExECAAYFAkLj7WcACgkQMoZOQZyFIitClACfWpH0+V/N6vuucWZ7bsMm2BcmM3oA
253 n3fF5qqovlog4/PcgvKCToNEF8uWiEYEExECAAYFAkLlELcACgkQUnkvr5l4r4YU
254 ZwCgg7vJpDpUXnuNvgc5RHgG7UYhRQYAoIEKHsrswh6XzVn5yQRkfjdB/A0OiEYE
255 ExECAAYFAkLlEaQACgkQa3OhBipiP3JA4QCffb8NgQssOQXaVR0dSwPCeU2nQPUA
256 n15EAjykVZsUi2tZWqEM08SNOKI9iEYEExECAAYFAkLmmWIACgkQaOuMdvjqKWd7
257 AQCbBpwyitQ77kd9KIT6y95Im1vmWt8AnAnkNTBctVtMfwddYTG+xLkaOllOiEYE
258 ExECAAYFAkLnYVAACgkQbpR1lMFSQxqIRACffQqUXTgOa4hyHYQBUwrlGEqmWt4A
259 nRMXVGhd47loS27MmiEiWwDlkNjJiEYEEBECAAYFAkOHn54ACgkQZjW2wN6IXdOr
260 9gCgh2fn26W0DSL5WZATvvQkwZeJNiMAnR6+0AlUK8uFSFIVhl+RZMnY+XFwiEYE
261 EBECAAYFAkWdnk0ACgkQIYJJVs5BnI/0SgCeKCw39INy9ISFunlAojYgSInHfokA
262 n2vU8q4JNjg13qNeclZN9kmN9mbWiEYEEBECAAYFAkY44sMACgkQFUWz/uIi3k+q
263 vACffppBpoY82MEvDV7c4/6cjw544CQAoJAPCdZA/LRqICJm0iFbDrwhsSb6iEYE
264 EBECAAYFAkY4558ACgkQY9CtrpESA+QrAACglRB/VdEmovbyWdMDmsTdyw4kha4A
265 n0uKwZeKHfBR3cC2s7MvqqmMoz9jiEUEEBECAAYFAkY8kyoACgkQmHDv8/EvYHIk
266 CgCYgXQZTJ8VmHwSX3pXOxnMhp7mbACeIPXwcPvmfP709nfgQ8/GpT2z9ISIRgQT
267 EQIABgUCRjkasQAKCRDh4fKwmQ7UqhZKAJ9iraDBstzeXPMtst3x+ZXdLQm7cgCf
268 WDDgaQOa8CoM5/+7WCtkyasP6BiIRgQTEQIABgUCRjxQRwAKCRBMBCgYMRo95eP4
269 AKCuEQU6fjPy/cPEiqhGH23J2YEr7gCfS8vBTEU4sRbOomTEuINPxb96OZmIRgQT
270 EQIABgUCRj2gkgAKCRAuuUaCiIF0AgOBAJ0bJmFzA9WkG5FmfaP4ieG9+SCbXACg
271 w+2wcOA/B94LKRtjhJT6j6zSiDmIRgQQEQIABgUCRj4VvwAKCRA+Km/CXymIJIvc
272 AJ9QSE4mCQldVnpbYwLTCk+xHDqhcQCggT9P3/rHIzIvv1tJ+A1ZJPvXOcqIRgQQ
273 EQIABgUCRj3WeAAKCRD1wmAWTO7XXwpbAJ4mr2IxFtx0ppkefxx0l0TJ6cFkrQCd
274 EFbc+aMxRKhK9SCAWi3mq1UqEWiIRgQQEQIABgUCRj31AAAKCRCgctTQQ1jFhByK
275 AJ9SIielTuD3StxPQpBkAkYP6Ld88ACgg1oPX9ryJA7YuhMD7byXQsETzD+IRgQQ
276 EQIABgUCRj4FxQAKCRACpaYFC35s+k/GAJ9/VDyw2vNzk1xjcu/QZCa3gGI2zgCf
277 eG8klJ78bAGknzxBlK3XtmoNqASISgQQEQIACgUCRjj3hAMFAzwACgkQc92MFgFT
278 AjVJogCeL+3FTTVR5snJx9qbGQsgv23ZaT0An2Hy1CcXVklcYBF7LbnbAgbe1Hpf
279 iEYEEBECAAYFAkZAtkMACgkQbQvHOkBYGDePegCbBe6rmz9/kYDV7w5pvwnugVsv
280 biEAniTfLW7NW8z1SRBWf6lMH3clGAs8iEYEEBECAAYFAkZMRFMACgkQHyEjw2vY
281 cqB22gCg1np1JYFYPqCB3ekZts3K+pn7RkwAnRWd6HmtjRolZdrZfkqQDJKmd5zv
282 iEYEEBECAAYFAkZMfQEACgkQD0UKJmIQv8DJYgCfW0C9rDAToLU+0BKLYCiWwtFJ
283 98MAn2HvQ3CDhv8WTm+av36lETLqhjnfiEYEEBECAAYFAkZSb1kACgkQMsHW7w8U
284 O8GGZwCg0l2T1O/OpOECXs/vYE2649wNTaYAoLrUpLKYev8uHAfc53lZ6LE0h1T0
285 iEYEEBECAAYFAkZSb2AACgkQy66+OaRsTKHZbwCdFSloWJh3uuTLk87aSt4uYeZr
286 KToAoIrN7epZxeu9n9e6hqVOLz85zc3TiEYEEBECAAYFAkZe1aoACgkQmobXzNGq
287 6mD+cwCg3k4BRrRi6pjrY/UggHjhiHWSD1YAniDQn1MVB620Ik2cVL7hR1V0ZL6b
288 iEYEEBECAAYFAkalTCwACgkQOb5RoQhMkROqQwCdHhIdklVR341azVFBO6aGArSO
289 P2QAn0WtSIiqaLTEQ57+ir62FxRYBQdWiEYEEBECAAYFAkatzFQACgkQM81nM69e
290 xFIdRgCfSGft6KIZ+CTEPIGr8lp8oOpNaHMAn1NCXZTJOW+r0G5ply4hlu8UXC4A
291 iQEcBBABAgAGBQJHwH2YAAoJEBllhVDDEQYRZ4cH/3XnLW6UAdDd4k0xl2lUAj9g
292 B7ITUbejCwvnFqUyKAE9P38boBHNfc6cliQUOz4ITWDPhiinbjNnJHglp9vK0o4R
293 /tFFyGImIvbmu1C8lyO2BJPgF2yMNrBgZhx0+IkAG3R4iy9JFIDGgddjLQSP4TX3
294 uRUFUXEAhHzGA//XP4tnC3CisvOsuoc6ZjyZGSt/HUzZoKf+wsdJlfabiK3QpD8l
295 SOw8KEZF54JUC8uaYGuBGs7ih4FcO+Aqb52UAx4/+13eEdAognVF2HbaiI+G2jEe
296 kyAwD0bP3DWyg+9fGBtnwtDMj0OrHklvA8qoHxAMvXHIGhxjqZBOFehh8DNEB6SI
297 RgQQEQIABgUCScqH2QAKCRDJx5JOUQR9Zj6WAJwOtRlhq45DedrYNH54QIJSFw3X
298 JQCfQI9fZl6zmKWSm1nJqXRC+awKmwyIRgQQEQIABgUCSc/UtQAKCRAkwaN4agF7
299 F75XAJ0TyTdCMGIZGCooM/xr3w+qvyZLgACg0W8O9WOf0qwSVgynmh2vQggUiyKI
300 RgQQEQIABgUCSdI2jwAKCRCusBoVO3x1sZHiAKClsXinnJfHMQYewFPqy16zr//f
301 4ACgulnu+ObADHMquuGCw4BLwrvqMIK0IFN0ZWZhbiBCb2Rld2lnIDxib2Rld2ln
302 QGJvc3QuZGU+iF8EExECABcFAjsSOYEFCwcKAwQDFQMCAxYCAQIXgAASCRCiEVrh
303 X2uLcgdlR1BHAAEByboAoNoD/9Jgm/alxfAYELz05LMa/HLeAKDWTHqq7rMkppZo
304 TUv2gWpVzrk5RIhGBBARAgAGBQI8PtWVAAoJEIEEZE9RiYUE0LMAn22/u01Lo3Bo
305 5lDxxHSkayUkYq25AKCm20yaGFGtTDJW4Rdz50pfut1AwoiZBBMBAgAGBQI+dd8P
306 AAoJED6Pt/L4g0HZWboD4gPGJi0y93+Zp37uFGgpe8PkB10HVLCe9B0l7R7BK0UF
307 hnFl004td2RWeALAAnOI8ZlxCahwQdUys34zF77c5fQ8Rn7co46wBSL59Oi/bG9/
308 wRYqBf13SWL2ITK1UDgzRznZrds9MLQqSL8oBjebyg28CZPBYH10FKigUUMwiEYE
309 ExECAAYFAj512scACgkQ7tHqOSJh0HOu5gCcDO9Ou8NA2+gChoNAn6j/J2owDxkA
310 nA0Q5AMezP7rKdsw+hCYqZSp8QhIiD8DBRA+daoh/W+IxiHQpxsRAiSnAJ4id/ij
311 cLliSH/EGh1UiaunYK9zLwCgyfeZ7mnhKXauba2NXFMlm3axSvuIRgQQEQIABgUC
312 PnekGgAKCRAVP6DNdaZ2kikaAKCJMBE/oJ/4ko7FRpUWvQv0MLmhRwCgjEXsPmY5
313 Ur8AVynVzE2TcEu12reIRgQQEQIABgUCPsouMgAKCRDb0kX8s7KhLABsAKCU2ntX
314 Y/DhTnvki6igzrvttl/ynACfZTZNwePs9imtT6phGTInelrsXLKIRgQTEQIABgUC
315 Po3ONQAKCRDKaTl0gQOjflg/AJ4khT+aic33qc/iMmMC5+URcxt6ZQCgleruhUJi
316 44Kpav9PdVbQMzdb52eIRgQQEQIABgUCQZLz6wAKCRDkE2EzDKpotDZHAJ4xwN/h
317 tv44yNFQnACTYsc322HjZACfTd9WoxRkRWY6tVd9YgumNc0swMiIRgQQEQIABgUC
318 QsUyhgAKCRCb8iNFL+KLz+ClAJ99ddEJ5l/VW/mKHvTITZleDSv+uwCglgqx3HQr
319 lqp+gTPKIEKPkjjom+GIagQwEQIAKgUCQuE4ECMdIFRoaXMgd2FzIGEgam9iIGFk
320 ZHJlc3MgYW5kIEkgcXVpdAAKCRCiEVrhX2uLcvEYAKCJD7CVpr2Iw657kO6G3Is8
321 xKa6IgCgiStyJgU5/dUEEPQctZ8ZVZSrHNGIRgQQEQIABgUCQt9FDAAKCRBB6gmg
322 V5NJj+d2AJ9QRCXhFzmee7cbhlfejg7LBsXsMQCfce2/Wz+if56L7WaZLpn893CA
323 zu+InAQTAQIABgUCQt6scQAKCRAxpj2W7BQLgXUkA/96klgNlfh+VTSxrwCUW1JE
324 5j87qDeJWrnN5ibVYPd7TE45hNeWQie2RgWGpsHNlDekVh9aZuHMJb9NzRGKAAJ2
325 augQQuvDKt8sge+ydRMXsLkAvpK4VBmobqqgyO0cV3ooMyizawMRndVcMbVu5b6G
326 kdj2tZEko/Nv9KBJ61MJ64icBBMBAgAGBQJC3sfZAAoJEDfj9F/uZeMhrGYEAKJg
327 LDFku3GdpF/BI4GQBKqadLygF3Igq9Np310sTcLOI2ARb4B18Tvq9CyR4PEvdlVC
328 5uEpaJozgHthTadjGTgg1WmiTWqG31s3U+zL5NLdK+k8qqrxGLzFzhk8PB1wJwIm
329 JcvLmJHm3HeIGycdEzn4swgmD4uI6p39mcGyCCONiJwEEwECAAYFAkLfbHkACgkQ
330 ms08wKmfdd2sxAP/e8W2cqyypPqYHs05nTxNzD5wLl72ABWvljfdf5mA97sEl3q4
331 8234j3sUN1Uk6c21NlK+eRBn8Lv1ihyLTJkACgdiXNFvi1eC4vLhQMGOPcGW8+wI
332 4olmsqftvG+2hNt4eCMead6IjAK7LNKgDWEBjGI+WIOvC5UJBO50cNXGOXWIRgQT
333 EQIABgUCQt667QAKCRAyyeTONkLLSxJgAJ9faCKziDmN6nQeMoAECTfVvIdTRACg
334 jnb3h8sc54gcosIh28qb7uBUuf6IRgQTEQIABgUCQt9sewAKCRBQjq7FMC2laDoH
335 AJ9VC11NFs0+BAYWoZBJSUEnjn3F9gCgsqGPrxhTBkHlWAh4iiumq31tZHaIRgQT
336 EQIABgUCQt9sfQAKCRDdumS6LDEtL3hJAKCEHj7lHAZHRk7LLbFQDh7oiY7plACg
337 iORbBhF3VWn1JCglbk51Kq5hJy2IRgQTEQIABgUCQuDJOwAKCRBc/Tf6zHjIk6wA
338 AJ4qjf2FNE1VXK+PnL2iFP1h7f8L4wCfbtoQqsaDE1vCrnSobEUT6nfqPt+IRgQT
339 EQIABgUCQuDszAAKCRDJtabs4td03yLQAKCz5pbjUWdyEHQr85R0He3QuDiLkgCg
340 z6XQ/LFLdcmwDAj4lsKbRpHdUDyIRgQTEQIABgUCQuDtQAAKCRBbloAQ4E+aiRuo
341 AJwLeKfpT6aqNLBvrusHnNNjROFi5wCgjhXup7RcdMNTDBY6BGj83NHuTU6IRgQT
342 EQIABgUCQuJibwAKCRBtmI0XhzFcMZwOAKCLkKunJnUNy7QgowvTkV+/DyU+FgCf
343 ScvQFzMSj1Gk1ViDbK0n5i2MpQWIRgQTEQIABgUCQuNVwAAKCRATLknU5B7cfur2
344 AJ9XnFPKjlIPsbrZVJRuNh96py7FfACgoC5yGwyRq9hYK3SMGGAu5MmQWpSIRgQT
345 EQIABgUCQuNk2wAKCRB1yqKj85s3UB1kAKClSCLmqecNSlVeFOwlSijhTjzmxgCg
346 5eYxuHJo4wf2D2d1gWbloc8xt/2IRgQQEQIABgUCQuRvFAAKCRCM43a4HNSGH1Jz
347 AKCoUQuAh01aTLbbUS4WCMrOAQblagCfdwFlsT48wWEBnJSFAiXaEcRtUkiIRgQQ
348 EQIABgUCQuSSxwAKCRAEkTRC6hujjcShAJ9EK1u8wehMaZLt2ZnexHICPhbtagCg
349 kN+i7LXBnm1IwlP5cGbmgW3BJRKIRgQQEQIABgUCQuXCIAAKCRBhGWouMz5OhEAf
350 AJsHEwc1jK9tiYBvWRMS3zJ0XrrShgCffOyuZlrBNeuO9s8T9WkL7/vCnOmIRgQQ
351 EQIABgUCQupj+AAKCRCyvrxAFSkkrxWDAJ9oJHjkm3MWfPS/iMK6iipoUaAfzQCf
352 YFygT+mws9MQIZEMoTi/sk0AOcKIRgQTEQIABgUCQuPtagAKCRAyhk5BnIUiKxsG
353 AJ4mMBcsZ/PlqEN2CjOoNits7PFYbwCeLuEXDDEcUAh7jb46wvrHB5EPjp+IRgQT
354 EQIABgUCQuUQtwAKCRBSeS+vmXivhlvNAJ4wGMXMO8EgWYrlU0i+9wrd6N0M/ACg
355 vODXK0oKDcDQ55t8xf2evmJA7HCIRgQTEQIABgUCQuURpQAKCRBrc6EGKmI/cl6+
356 AJ4kaPB7Ois5KuLwhbEwmpO3e07OQQCgw1kJOjcCZwogIWG1222By45k1YCIRgQT
357 EQIABgUCQuaZYgAKCRBo64x2+OopZ+DxAJ91h0aGRvukGqAWEafe4nnT6xj9CACf
358 U91kJ9G1WB2T8lW/fkXt8mnlrUKIRgQTEQIABgUCQudhVwAKCRBulHWUwVJDGgmC
359 AJ9DsO7lkpvuigmPoIX6d7vufFW5iACeMsXW1nX0DWf6E9pPgDaeZ+dba1GIRgQQ
360 EQIABgUCQ4efngAKCRBmNbbA3ohd09++AJ9GFjNIUutctozuFNreIeS2xATWJQCf
361 TUwt6nd4R13f5U0+iOsTwWVX6h2IRgQQEQIABgUCQ4efngAKCRBmNbbA3ohd06v2
362 AKCHZ+fbpbQNIvlZkBO+9CTBl4k2IwCdHr7QCVQry4VIUhWGX5Fkydj5cXCJARwE
363 EAECAAYFAkfAfZgACgkQGWWFUMMRBhFLagf6AqFi2y+DPg+duogX5hHslLpeRVXb
364 qEqX9bB2BzzinUhTmmRpEpiVnCkTd69scXh/ZVTECfA2zBYV67gp3eitUB7CDSeL
365 ZwqQCIz42uF5ADq9oj+j6uf8pPmsk9qO4VZcr7mUwJ4tDy6znG7Qg5H7y4HRRQ8c
366 wodDIa2jpLdQ+v9+fms4Nq5j/IJRmHjT7Ha6n78arpl8DlBtjjG0dpmKfBB9n68M
367 biFLX19yIxO98X/nEoDCk6DuLX79Ratt4jEr08YCyJ4PfAqJKUy+F5jrKnp3G/qj
368 6H2N72vHZLzoZRfZjBzbpN3V9rPossxQauoRqmU5M9wFDnBoqyszMMU+KokBHAQQ
369 AQIABgUCR8B9mAAKCRAZZYVQwxEGEWeHB/915y1ulAHQ3eJNMZdpVAI/YAeyE1G3
370 owsL5xalMigBPT9/G6ARzX3OnJYkFDs+CE1gz4Yop24zZyR4JafbytKOEf7RRchi
371 JiL25rtQvJcjtgST4BdsjDawYGYcdPiJABt0eIsvSRSAxoHXYy0Ej+E197kVBVFx
372 AIR8xgP/1z+LZwtworLzrLqHOmY8mRkrfx1M2aCn/sLHSZX2m4it0KQ/JUjsPChG
373 ReeCVAvLmmBrgRrO4oeBXDvgKm+dlAMeP/td3hHQKIJ1Rdh22oiPhtoxHpMgMA9G
374 z9w1soPvXxgbZ8LQzI9Dqx5JbwPKqB8QDL1xyBocY6mQThXoYfAzRAektCpTdGVm
375 YW4gQm9kZXdpZyA8c3RlZmFuLmJvZGV3aWdAZnJlZW5ldC5kZT6IXAQTEQIAHAUC
376 PmiBXAIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQohFa4V9ri3JPKACfXhFOr4gM
377 MIQwEGvUb6J/X4asuzIAnje2H9T1r/jSVi1NbIEtQfbpmyQXiJkEEwECAAYFAj51
378 3w8ACgkQPo+38viDQdmGkgPnUYJfHlDrQ2jYJWuPDve9n4pV9OvyIllKyLdfULjs
379 LWXw4Jm+fMQJgWr2GEov1ZYIyS2+rGDZpbz/vxaBVbgqM8TPdiXzxwU8AFq4k+Em
380 4fKXR58ByLSJjvLLza61spNHJennEUFp3tTpEsr4bNuuaoRYhtiKzTqNuoC+0x+I
381 RgQTEQIABgUCPnXaxwAKCRDu0eo5ImHQc5lcAJ9FOoAL4uHMuqHXrrxsEVPJvEJ2
382 /ACggaOR62EziUqcqpdm/1Zy3P4T22iIPwMFED51qjj9b4jGIdCnGxECWssAoKnk
383 R63bWGCFDB5YJtfZJ+nQq3TAAKD1bzG/kITQpIHsT2vCY1yBmlWbBYhGBBARAgAG
384 BQI+d6QaAAoJEBU/oM11pnaS+9IAn0kFlXAzOhhu4r5fglMVuw5bTAd0AKCtYRX2
385 ESU/+tsE8vuXWtsMCGeI5YhGBBARAgAGBQI+yi67AAoJENvSRfyzsqEsSccAoKqG
386 39X2y6xoQa56nviF5iCj/oTFAJwLKx9GyKEUbSM9f/IQ7AsZPhHT54hGBBMRAgAG
387 BQI+jc41AAoJEMppOXSBA6N+xYgAn1HbGamcXTDYSFjn3U5ik2vQa8nuAKC/uUM0
388 1gsdn+71EiAkmrjlH6H9MIhGBBARAgAGBQJCuAqrAAoJEIEEZE9RiYUE0MUAn3cW
389 FVW03CDuMuA7TSUqTf/eWARWAKC/GjQnPZ0+g7NbDw68ZSY3k8WuuohGBBARAgAG
390 BQJBkvP5AAoJEOQTYTMMqmi0GIQAn1mpdHz/wV++rSU2Qn7R32slfNdpAKDJPqpn
391 mcN4MUmk90yZEeHAdJmrhIhGBBARAgAGBQJCxTKGAAoJEJvyI0Uv4ovP3YUAn1z8
392 L1EnLdIYttWrT1zs0E89Lz4BAJ4sFzcSq2NO3OZsEQfh9F6CrUe3UohGBBARAgAG
393 BQJC30UMAAoJEEHqCaBXk0mPIUgAoOF/OCzco+n/3sGJ57m0+aqGLOwjAJ9bC86B
394 2hRvkaZlGm/ne3TzCgFGnohGBBARAgAGBQJC4DXTAAoJEHPOLvuECPdVsEoAn2hq
395 8w0JUtfJpu3SmMUkFZLBFm3+AJ48pxmjHXjoBJGpokXw4i9Cfb56BoibBBMBAgAG
396 BQJC3qxxAAoJEDGmPZbsFAuBGDUD93nHzcDWR6AuDxDvaDp1xR8oJZHojeZ9sWSR
397 QffiNJKF07vvdjGbygqiWbQmtTM9qBnAxEiBpSpJemBhvGTKivPkb9H88KQe2jqo
398 wDO3IJorIVMT+eUFB+4pn5c+kFLD/IhG7ohZ2rBIc47L62FFuD19esxvMcVelrBF
399 q67ZV4KInAQTAQIABgUCQt7H2QAKCRA34/Rf7mXjIY9vBADqrguzlNOJFkWvEkgd
400 VXCCH2TP3OUuPZ9JQtbJfbkg1nn1hCnMITapNJlEE3yyjB7kEpBkmUtyKv3VSwOD
401 spfis/ps6zJRIne/2R5xqtT38Hf/sYucoMZUceipFAoCLYOqkKJKwTpYM0401dUp
402 uxp1y8Lq5N0SDtTW9fKMNs9jioicBBMBAgAGBQJC32x5AAoJEJrNPMCpn3Xdek0E
403 ANLj3wh2FCukydsfSzqgjFDpkVjiBxbTtCep86flaLMrF3H0idckGCjMUf/JostB
404 sjwCpL2VlCtvhwl5ZgIzm8luceHupq2iC5hvUN0IjKuIXMLbZP7DE+Lfcvw82nKt
405 8JNPpjosXiMhysQZms2XfuNP6f/Ey8J5jaB2Z2JCYWJBiEYEExECAAYFAkLeuu0A
406 CgkQMsnkzjZCy0vBrgCglfCttIxFGqVTLTq/nhPnRFMHX9YAoM4Z05oTuPFxGWS4
407 RzxCzCb3vpsAiEYEExECAAYFAkLfbHsACgkQUI6uxTAtpWgipACfTBzbyb7Vc0jr
408 2FZDiXJFUSBCoEYAnR+ySWmedkcJWESStqRstD8T72mOiEYEExECAAYFAkLfbH0A
409 CgkQ3bpkuiwxLS/5RACgm88lpYDxy0bYF9/ubFbvqCw6i9YAnjrQoOLRBtQ4QmIP
410 R+T/9HReOeSciEYEExECAAYFAkLgyTwACgkQXP03+sx4yJNXxQCffoccUBWO51YI
411 EM0mbsqpnKHtawoAn2xTiDgo3TjtbRJskADuw+QnATQLiEYEExECAAYFAkLg7MwA
412 CgkQybWm7OLXdN8bPwCfeKtfQWKm8i+KuFJTIoMTvAN65QQAn2A9G1wtEN4Vzg6H
413 fnTvtgus32rRiEYEExECAAYFAkLg7UAACgkQW5aAEOBPmonAkwCfeF3l1lE2WijQ
414 F0BmPMfqvkyA2UcAnRQzuc7PWyP0nydGoJvfEUHByVs7iEYEExECAAYFAkLiYm8A
415 CgkQbZiNF4cxXDEC6gCgqICh/djzt1i6uadJAOztZc/zxl0AnjR1OaM2JxR+wqK3
416 loSTEKX1uOpBiEYEExECAAYFAkLjVcAACgkQEy5J1OQe3H7rRwCeJWLmLyPzpg3n
417 r65j7AxqGRJeDfUAnRT2Oa85dAM02wgdYlj3FejPuNFziEYEExECAAYFAkLjZNsA
418 CgkQdcqio/ObN1DA+gCeOaeMarEJDPbZjaN3y/Pf5PB/Cv0AoMGPjPSTGt/iHJ2a
419 Arfyd0ME/R52iEYEEBECAAYFAkLkbxQACgkQjON2uBzUhh+lnQCfVbPGF5UWlzFb
420 xK+xKmY2DbKXb5wAnjpoAxffSRO1PZlQUHgWlS+NaeCziEYEEBECAAYFAkLkkscA
421 CgkQBJE0Quobo40fbACgo9YCJXu5Hpoc/SVp3rHCYmTuEMYAoIt2q6rPL/Jbbkik
422 bRqausEnFstziEYEEBECAAYFAkLlwiAACgkQYRlqLjM+ToRP8wCeOVAIpaG+q9G7
423 uJgVCyDZ0JbjjfIAoJgg+NrBfhNeOBuu5mS1PSGDztQ+iEYEEBECAAYFAkLqY/gA
424 CgkQsr68QBUpJK8HfwCfWgNlYNLBWmn/nejlx0m6NstT2CsAnRdhsusv6RbcKNoV
425 UudxGG4Xm3nGiEYEExECAAYFAkLj7WoACgkQMoZOQZyFIiv6jQCeMior8Tg4msrR
426 c+FfXfj5Uln03d4An3RTaHKU+Sv4SgEecXlW0RYlVa6eiEYEExECAAYFAkLlELcA
427 CgkQUnkvr5l4r4ZC9gCbB5X0rL/DtpGptiNO12DdTQqzsMMAoOWpJFg3W7zAr7al
428 Vjqlx0t1vS4KiEYEExECAAYFAkLlEaUACgkQa3OhBipiP3LYawCgiuQqhVay7FE8
429 e05Za69seQwF4CYAnAxBVNyvXu/1aeAuSi3iC6tywvFoiEYEExECAAYFAkLmmWIA
430 CgkQaOuMdvjqKWfdbQCdHfDneYM+nWXT/oYOqohamLvk8iQAn1LLJhkLiCMOa9/b
431 iF24zKt+MjaHiEYEExECAAYFAkLnYVcACgkQbpR1lMFSQxog0ACgp/m7d/NdNP0w
432 605VyrJWCdogeG8An2E+FpFBQgyvJaD6klzDRNNYLc71iEYEEBECAAYFAkOHn54A
433 CgkQZjW2wN6IXdNgDgCfUVMGJZV/D1QEdnwrTkRmMb37KR4AnRLDWMsKtq4qKXQj
434 YbmuLNdHa1EQiEYEEBECAAYFAkY44sgACgkQFUWz/uIi3k8H/ACgmKEdToiBaw1w
435 AMXXKjj+8PTU880AnjTWDVjV2fZnj8iXaOK7MTx01gMRiEYEEBECAAYFAkY456IA
436 CgkQY9CtrpESA+QXcACcCFtUvEcmTT5ezAsMsWPbRJAqtwoAnjFdqKAoBDkPr85/
437 VI89GhfttMRdiEYEEBECAAYFAkY8kyoACgkQmHDv8/EvYHLdewCgo42arxjKFiq+
438 lp9b11fuTqvimDkAn1KOSLRaqubUBhfEBgZzx9kh6wh/iEYEExECAAYFAkY5GrkA
439 CgkQ4eHysJkO1KqIOgCdHwUD/IZcQB3qA/QCiKjIwePp7QoAoIB2fFdQH95LA33w
440 SR5XBI+mIEsbiEYEExECAAYFAkY8UEcACgkQTAQoGDEaPeX5dgCfY6TPlbpJpsrK
441 KtQaMXfSWv0E/xUAoIGqw9ZHnQ7y9wbSUMuSnW25b7rdiEYEExECAAYFAkY9oJIA
442 CgkQLrlGgoiBdAJMWQCgirz2diHoCbFyrBAV5iKWgP4Ua/QAnjWVrS+SKzUlQgMz
443 cU07zHDlVs1kiEYEEBECAAYFAkY91ngACgkQ9cJgFkzu119zGQCcCwwCeGu9A1U9
444 Amz8/nKxBModdnsAoIavFQWLkVD3egS5YEarD/Edwx9UiEYEEBECAAYFAkY99QUA
445 CgkQoHLU0ENYxYRKfgCeMfNpqkkRohgWFz/f2EhGbmfR2X0An2UBeqbP5hBKokpD
446 9xyF0pst2FIZiEYEEBECAAYFAkY+BcUACgkQAqWmBQt+bPrGDwCfUQUaIJ4jUL7s
447 FQOojnGU+mzpYHkAn1xSgTyDWKkT9C0JVhw5SEPnfLFjiEYEExECAAYFAkY/BjEA
448 CgkQA/aMvd6IhKCNuwCgvN28t3l3yYAMxkMUuL3LA8uTikEAoK3bfHFYDA1KPlb6
449 48YsvpHQgRvoiEoEEBECAAoFAkY494cDBQM8AAoJEHPdjBYBUwI1PekAnR36SmoX
450 YYegiEUSKxHCjHQnnYnbAJ9zmdCCloaaDIyqh2qr5x2jJscjHYhGBBARAgAGBQJG
451 QLZMAAoJEG0LxzpAWBg3YX4An2XrLaazjvwgpUwVEj9KCHAq9FYBAJ4khHqEJHjp
452 BjQioqGQfL2Z/NqI9ohGBBARAgAGBQJGTERTAAoJEB8hI8Nr2HKg6F0Anjm/ExEy
453 BoePXnjwORS20+/Rx1gdAJ0aVz/9sdWcnDCVQXP/U7ixfAO21ohGBBARAgAGBQJG
454 TH0BAAoJEA9FCiZiEL/A7x8Anjgvd31Atoy8y9wjvxowEkfbLZ1KAJ973Fhgy5i9
455 /2oSWKGKX/tr/2nrwIhGBBARAgAGBQJGUm9ZAAoJEDLB1u8PFDvBEgMAn3Gjh6BS
456 BWjqH83sDmcwG5Pd1nqMAKDLY5za4VhiEa8ECBCkeoRJl/iy44hGBBARAgAGBQJG
457 Um9gAAoJEMuuvjmkbEyhglQAoL+JREGW7kkrFkmpQnoPaTNi6ji1AKDFOm+kNYqq
458 sYgzw54D89t1QmpOQIhGBBARAgAGBQJGXtWqAAoJEJqG18zRqupgx3wAoMcKQRL6
459 tnmUztp7C5X7+i46ScZAAJ948yxdrkvg4qMDezOdydmRxzpaXohGBBARAgAGBQJG
460 pUwuAAoJEDm+UaEITJETPdoAoIVf/V5humFKY/Yph+AeSGDod/VTAKC2NmslQ2e6
461 Gw8ZEr4Wih52zcxq0YhGBBARAgAGBQJGrcxXAAoJEDPNZzOvXsRS8j0AoLVDN8Wk
462 RLiuBvr7qWrNhg7Ylb1LAKC1mSGqxofl69FmIiCXOMeZ+A8mN4kBHAQQAQIABgUC
463 R8B9mAAKCRAZZYVQwxEGESOgCADhwUA+q0JhWkR/Q1zt5yKrGlQsYtpQI64N8xmL
464 PWRKReLgWIMAptJ+twYA+YuH7wCJBsgP7U8oi2x9azlmO4HMnDa2gXs4pJbE0pRI
465 mhP5JqkYauzepvLBlZGLzZ1zCpLE/JmaxB8tc40lF4/CBbLj5EE2+jfyPWEplyV/
466 zEwjjDXAkxSzfhdp70EYyguGm4n6M4KgbgkTdxR1/uG+HIkq0yHGsCJhViZWW6tK
467 G00XcLOGrm2bzQlv2bXCVlEWC9QTqb/ZdbA+ONLSWdmegEVVnQeUx3jtvRg67yJ5
468 LXA2CSq2lHAGoEEfZc4ziRHmn+5Pusk33Jq/rPV8QSCZXlMbiEYEEBECAAYFAknK
469 h9kACgkQyceSTlEEfWbGtwCePr57kk5WrDbIcRgYgvl37P2JRF8AoJHpjz2MwXPO
470 /asQ9sCsLE54aa6utCRTdGVmYW4gQm9kZXdpZyA8c3RlZmFuQHNhbWFmbG9zdC5k
471 ZT6IXgQTEQIAHgUCQpxp5QIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRCiEVrh
472 X2uLcsktAJ9XkWAsu0zJ293dGa+Yban+Zr1V9ACg3b9Petds6ebqQZoiHRopckbb
473 OLqIRgQQEQIABgUCQrgKqwAKCRCBBGRPUYmFBP0VAKCPH0b7S+TylV1uBuYcYnWI
474 b/RJzwCeJvRTMPnWNjVz+CVOvVzJTH4ol5mIRgQQEQIABgUCQsUyhgAKCRCb8iNF
475 L+KLz3iqAKCXRZWdGjBVbj3IBFl3kvh3xF2gsgCcD3H79mbVDRNMxpGArFQ1hqQF
476 zleIRgQQEQIABgUCQt9FDAAKCRBB6gmgV5NJjzHQAJ9IfkjKkiEuFxUhznsghAQ8
477 bsBWnACgoT0kWSB3iUepLIDoWhhGtDIS5FSInAQTAQIABgUCQt6scQAKCRAxpj2W
478 7BQLgebOBACAFFpEKETO3ZHbjMnPogACNr6EZCQxzGTIXrXSyWQs68VcH54wUOA4
479 yk3cGpfH2pgAxYjaHejTJRvDKvGrPGlKHgCZFy4+wHzo17pW9J1aKk2sUWlT67sn
480 DVdMun/i8WxD9yz299cXR6iCxPfP2HIMEqbsxWJaXITo7drWSjO35YicBBMBAgAG
481 BQJC3sfZAAoJEDfj9F/uZeMhRawEAM9wfn9sBIsFzQRQbAO+ll83f8ki++A4Anj6
482 DXQ4xRmClUxqahL1BjxxeQhE+Qomq1IebDJr0Se34XB0g3J7bzr/i9QmEwEqnDJf
483 WVobv1Ugjy+1jzErlZBhm8hnCI+zPnrWKLk0n78vzJ5RrnVaTTV+OW5r4rdVZ86y
484 KYHtpVSoiJwEEwECAAYFAkLfbHkACgkQms08wKmfdd0HDQP8DDD+1FQU8PPPe+Ku
485 f2bJOO7Ycrej4JF1I/Gbs2HH3xXgOZsRv6WJ41M/ovxJLYrpVqQA2YF/Gxwguwrf
486 4lPk+4spFdabguiJK0d2/KZAtnLsjIzdYcoY01IKGT3xkPwIDErNFSmxX6bKCUeP
487 cFNHYZ6dDBHFFcYVTsdo/wbAe6aIRgQTEQIABgUCQt6wsgAKCRD9b4jGIdCnG30U
488 AKDCxsPZksKIcvj7tbHQEwm+PV5+DwCg7PorUCgIvTIWnID8zRWDBG4ACXaIRgQT
489 EQIABgUCQt667QAKCRAyyeTONkLLS/d2AJwM7BQIQgqLA0qA75R2EjHFXQKZWACg
490 o7iaANHxIRc/Nw19j8CxNbWJRJ6IRgQTEQIABgUCQt9sewAKCRBQjq7FMC2laIx3
491 AJsF0Hjrm4N21EwdrmhS9PHKQL2KdgCgjlus2GyuCzafgb9JHVhBDrhelkmIRgQT
492 EQIABgUCQt9sfQAKCRDdumS6LDEtL7MWAKC6rQU6ZjSS6gVnwswutaqBwfwtvwCg
493 v2mMGJf2hnYVaNNqV5WIFAuycmOIRgQTEQIABgUCQuDJOwAKCRBc/Tf6zHjIk9Tl
494 AJ9dbM2HowI5oD6hGSnADhI2dKfBrQCg4O9WtFiRzLqC1TgCAsbigqy+JDiIRgQT
495 EQIABgUCQuDszAAKCRDJtabs4td0311pAJ9L3yUe7GUeDqMzd3WLWatclf7ruQCe
496 OenA9nhyKgHASeEK/ZXQXDDBW0uIRgQTEQIABgUCQuDtQAAKCRBbloAQ4E+aibNV
497 AJ4wnAfcA/rtUs3+Hu9nNn8ar/2Q5wCfe6W+k9yHjd7hZWnYHdnCkAZkOMeIRgQT
498 EQIABgUCQuJibwAKCRBtmI0XhzFcMezQAKCnk+So0Anm4kLDwl+srHvIB7b6jACg
499 qROBN5MeEGXQm+Gan2VSt+nvTZ+IRgQTEQIABgUCQuNVwAAKCRATLknU5B7cflR0
500 AKCTAlfhPFwHPXnBo+5IROopwNQnsQCgh2vHS9VRZRt5I9isNDaNf1biCQmIRgQT
501 EQIABgUCQuNk2wAKCRB1yqKj85s3UK9XAKCELi7ymxtLxdwYfdfV3dxd63mV2wCg
502 jgaUlQqFXjx5mXnRsgy4S6cS9yuIRgQQEQIABgUCQuRvFAAKCRCM43a4HNSGH5/s
503 AJ9JVHMVwBwHD8PN3DQq8hHEumn8twCfVQSXooNY2P744K+8k6lLO8nOH6GIRgQQ
504 EQIABgUCQuSSxwAKCRAEkTRC6hujjb+qAJ0Z+AoGDYe122wRAOYAKayl9f9e0QCe
505 Ketoll6NZ+Rm/NKbFJGP6fYywIuIRgQQEQIABgUCQuXCIAAKCRBhGWouMz5OhDd7
506 AJ40l37cLZcSxfPt3M7/aOPgVGpa5wCfciaEynzuHDfIQD/vtXrZb2m0+NeIRgQQ
507 EQIABgUCQupj+AAKCRCyvrxAFSkkrwQsAJwM8IqtXQk/TBiQi6Fyq/HHm5/zvACg
508 5atZV8F+r7jVRhT1SJ+FaVsaQDiIRgQTEQIABgUCQuPtagAKCRAyhk5BnIUiKwuy
509 AJwOljL2++fVQ0BSKRvFSvS+fSu3KACeJxsOhbyCd3o3rqwaVeY5FFi+Fm+IRgQT
510 EQIABgUCQuUQtwAKCRBSeS+vmXivhv0OAJ0Sg/UEnB/IAoqjHzKoBivCMYDtrQCf
511 VY3IDKRHbbLNfWBSDERWCTpHXtiIRgQTEQIABgUCQuURpQAKCRBrc6EGKmI/cqGB
512 AKDEgTewzt6TjmCkI9RrYjF46a9H4wCeJPh4bmTymcfwRGn60h0a9Mz1mKaIRgQT
513 EQIABgUCQuaZYgAKCRBo64x2+OopZ3lEAJ9w4EWAgRUMxf0Ud1zoygYDQedAgQCe
514 JPHSbk62Ej11NljNGN1zdwzRHuSIRgQTEQIABgUCQudhVwAKCRBulHWUwVJDGkOf
515 AKCgQM+50dTktJDaDd8gVOGBKRiSIgCgkT9gdtDac0m9s2IHAqktk0mc0U+IRgQQ
516 EQIABgUCQ4efngAKCRBmNbbA3ohd05uvAKCjMnn4GpnZhjWFS7iN0LIXgxm5PwCf
517 YodjKF5zSbIROx79dJ41Gg0/VxWIRgQQEQIABgUCRjjiyAAKCRAVRbP+4iLeTznP
518 AKCaIUKdiySarhu//zEVn67y9q/szACcDUob1L2ac1R1FHB9XE4fTf/PV1KIRgQQ
519 EQIABgUCRjjnogAKCRBj0K2ukRID5FlVAJoDhc0dijUvPmOKILkX6fG5g73DugCe
520 PsOrjW+YIc5+T9qeVMzHyfm2opuIRgQQEQIABgUCRjyTKgAKCRCYcO/z8S9gctnJ
521 AKCc7DZ7JzXgaB4ImiwB2dyGMFUC8QCgitOFKEw1y4+V1dNN3kZYL4P/M/uIRgQT
522 EQIABgUCRjkauQAKCRDh4fKwmQ7UqvVYAJ9BjHLDyGmR56xKlKF3qVq1+jAmgwCf
523 QR+0qbVWaSIaVS1DCg8yUr2txOeIRgQTEQIABgUCRjxQRwAKCRBMBCgYMRo95VO1
524 AKCewEwAscfj9VfTxswF6BL6zNj8rACfW/3kG7zPI2dSjWJzGYPQYPAa0smIRgQT
525 EQIABgUCRj2gkgAKCRAuuUaCiIF0AjxRAKCu9kiQfvVmSrVZb9HK8Mazhut+hwCf
526 Y5guSOz96KH5dJ2585cm5wPyT5mIRgQQEQIABgUCRj3WeAAKCRD1wmAWTO7XX04y
527 AJ4/ZvOfsexCgIQRuoREg1/D9bniKgCfTcKh9dLFkPjlD3yIw/NCc1L0/ruIRgQQ
528 EQIABgUCRj31BQAKCRCgctTQQ1jFhJmBAJ0TPZlIksq1EnAYtTTSb/tHpXxNUACf
529 d/m3jaTHdJljRXGI7UBsVHnL0nWIRgQQEQIABgUCRj4FxQAKCRACpaYFC35s+iQn
530 AJ0eGzB7NIQtXLEgyuphyW0nBppVrQCcDj6tm1MCKXA7f4zV1R0u30jrUeCISgQQ
531 EQIACgUCRjj3hwMFAzwACgkQc92MFgFTAjV92QCeI+02yLkSqmdJlMBVfVE9joT/
532 pBAAnjJlywot38PS8FtodliCfNvqn6VIiEYEEBECAAYFAkZAtkwACgkQbQvHOkBY
533 GDcfVwCfbS6bS20V1ElnuQBAofsmi0yjbzoAn3eztrDQIrh+/BkXIJo7IF0Ny+gV
534 iEYEEBECAAYFAkZMRFMACgkQHyEjw2vYcqBPqACg1jy6peePfEuvYJEKfJBNG7FV
535 wPwAn3y5/eBtZdRefj90FeIiS3dr3D3siEYEEBECAAYFAkZMfQEACgkQD0UKJmIQ
536 v8AfLQCfeHzJB6tJdA4bjPEcJKi0sMFceCwAnAovkjdUhF2aJrpK2cr4bZhm5Rbh
537 iEYEEBECAAYFAkZSb1kACgkQMsHW7w8UO8FdFACfSFzmzz3lZmB+qclUq7q+YVgd
538 3hYAnRyNi3iYLUVrk746XsvzWcv8UonRiEYEEBECAAYFAkZSb2AACgkQy66+OaRs
539 TKE0LgCfYZfXtB9Er7iKXoDfhNuuDIdKmqQAniGNC3piLBCggMPpJ5vQp2KsptvJ
540 iEYEEBECAAYFAkZe1aoACgkQmobXzNGq6mC8pQCfeV2ib+Ymo/KQ+jYsr1BxYVFC
541 OmsAoO312vLgv8Q46hucGIq9aN2isEnEiEYEEBECAAYFAkalTC4ACgkQOb5RoQhM
542 kRPl4wCfebfolpLZYdGk48JuUwd2shtkicwAoMGAdNOSoXynI/6/b9jsxQl8qmwZ
543 iEYEEBECAAYFAkatzFcACgkQM81nM69exFIBlgCg0CUQ1h61lCLBjE9+/Kvskrh1
544 QAgAn0gXeq1NKEuepDB6hQo7fVZrSpF8iQEcBBABAgAGBQJHwH2YAAoJEBllhVDD
545 EQYR8ZEIALAYFxipk7FfpDbEnUrTI237QugKjpvrX9n7CdHxJLnwOBr1g2/e/RMg
546 oJHH8yqP8iQPGMfZXCVLM6ME/EoUQAVT0M0I1QsBVxTIXyPqQIzCv6zibLYyEXDl
547 QDNVB4hqdhozzxyjGruqbn75zfb8mlTMoj9lElNhVIdcUOVL2xHkBy6g/YpmuZb/
548 pt4HXBOUyWkmFK8zBMxhXw5bOuOP2zSJk9rZt7wdKNj3iC+/+936yXZzqWFuUOq0
549 RX61RtW8e3SJfowGFBd728snsiD0IFLTXor62aBfBJ5yiGKFUBM8LQ27FcJasfo7
550 a8SiBbJOO/OsyQ1lRvLS85kM+XZDXZaIRgQQEQIABgUCScqH2QAKCRDJx5JOUQR9
551 Zlt8AKCAMAc8652qgKVPdH0XJbzoq6ykNwCgkTboPY7d+GFyEwNCHk+0PAmkPru0
552 KFN0ZWZhbiBCb2Rld2lnIDxzdGVmYW4uYm9kZXdpZ0BlcG9zdC5kZT6IdwQwEQIA
553 NwUCQsVK6jAdIEkgbm8gbG9uZ2VyIGhhdmUgYWNjZXNzIHRvIHRoYXQgZW1haWwg
554 YWRkcmVzcy4ACgkQohFa4V9ri3LW7wCdEc6hdCr094a8LG+chTd+OzGxfFUAnR3F
555 vtuG8sv367Knk0ybMnpOM/4hiEYEEBECAAYFAj53pBoACgkQFT+gzXWmdpL1ewCe
556 OSe7lOufhc3mfTXs7eSvqECt89oAn0VM+YgQHbfdVp32YE7Ht6N6GPf0iJkEEwEC
557 AAYFAj513w8ACgkQPo+38viDQdkP7QPmPZXPi7m6wRiLofsTlHCbBrR+ehWoSSqC
558 mHQjN1DGRtamGE6X8QbMIttD+NLp+uTx8j/E0sGUdPnWkky6fwt1f3AYeoAgCXNv
559 PoewsC6mZn3FMdEo6vJc43FmhsUfumOtunvGNBnXdM8GSCJ+RBS/ASMjRrECF12/
560 14xwgyyIVwQTEQIAFwUCPD7aNgULBwoDBAMVAwIDFgIBAheAAAoJEKIRWuFfa4ty
561 s/4AoND5QhEdyVIypBvCUHv5SCaAKcd/AKDFthtZTrjF+eEYlktPLRtI9zjeE4hG
562 BBMRAgAGBQI+jc41AAoJEMppOXSBA6N+jAIAoIcAeCIKt2QBPnAthnUk4DhlmM7F
563 AKCA0Iz9ZutXGb2l+p8s7hhF3+Y9L4hGBBMRAgAGBQI+ddrHAAoJEO7R6jkiYdBz
564 i84AnRddvByuDodl5KaCSdpe6k9aYkLqAJoC/ud28X0M478KlmacVVjb+PqzBIg/
565 AwUQPnWqLv1viMYh0KcbEQJ6DwCff918LRigFUyEvYj04C12so87JNUAn0RNFw+P
566 1/SR9Mr/JQmOzJVhlwdriEYEEBECAAYFAkLFMoYACgkQm/IjRS/ii8+wZwCfRvfW
567 6NyBoAp7oS9ILRHNYh2GbhsAnRYGs1hSaGK4rGxm/fmqxj+DvqI2iQEcBBABAgAG
568 BQJHwH2YAAoJEBllhVDDEQYRqFAH/28B/f92MsQX9ZRJG1v9EDGVx1U+pcE16a7i
569 plCP4QuUR6uA2EUe9fptzZfX2iT2nr2XgCB3x2NHf0rzNpTAM3OtqKQhXdvS3EWz
570 WqR8UaDf6dxKN57B4QONRIhuImf3m9DWFNwIr3oOtO25Q+tG7YcZen/zbwU5O23C
571 EakNsysxGEHn/3BPjRyA1FE7NVLrAmxFu8LXBUD9y3HNNetM4WlucnObqw5cBFsZ
572 MtnGcVLs3suTAsxwrnBo7jq/DbZVvzUZtEkGdV7LpSWkivSrq0+h9Gzug8EcYTjr
573 dR6LFA5xGan6R9zrSe4mxe7vja10fmGEdIOQIapgO/iOWDR83MG5AQ0EOxIiVBAE
574 AM1SlkvEK5MrMnW0ybtv9eMCG89gqIvd2gBnpcAsF0sX+dCaWHWNy5HL3dBak/G3
575 BJ8+NzAksfL5Srm0LVKcfVjBiG+IsbUoSyeJQGuhSZXYcnIc/3Z8Ujcs+TfFurG8
576 uHU1cWnNK5aMYwDrqxmp4Ru0zLYHw4tHBBKF0cgFaCsjAAMFA/49aSZuDaatppSa
577 BOzCt7wIYCsGBxX5ZibrJqr0gLUbhXU9eaWzCawOWwCvpQN0lTjoYVkwiLZaYUkd
578 qsSQgHAU3jjKlIuaIRXApEkTb8Jg7R/vNAdwXoZRLBCjZPGd5qGtnIezsZ2+lxFx
579 +bRieUL8fUInemXwWl8e23PMisgm+IhOBBgRAgAGBQI7EiJUABIJEKIRWuFfa4ty
580 B2VHUEcAAQENMgCgnc22kj8TfjktU6u4SUUqud25ZZcAn0B2b0zPjKjGuiwdKSnk
581 FbNcFS3g
582 =LIse
583 -----END PGP PUBLIC KEY BLOCK-----
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
0 XMLUnit version 1.0
1 ===================
2
3 To run this software you will need:
4 - Junit (http://www.junit.org/)
5 - a JAXP compliant XML SAX and DOM parser (e.g. Apache Xerces)
6 - a JAXP/Trax compliant XSLT engine (e.g. Apache Xalan)
7 in your classpath
8
9 If you want to build the source code you will also need Ant (http://jakarta.apache.org/ant)
10
11 This build of the source code was prepared using JDK1.4.1, Junit3.8.1, and Ant1.5: it is
12 not binary compatible with JDK1.1.x or Junit3.7.x. If you want to use these older libraries
13 then you will need to rebuild the source code first.
14
15 Enjoy!
16 http://xmlunit.sourceforge.net/
17
18 Changes in this version:
19 - DifferenceListener interface refactored: single method now provides the NodeDetail
20 of nodes that differ when a comparison is performed
21 - NEW NodeDetail class added to supply details of compared nodes including XPath location!
22 - NEW ElementQualifier interface added so that documents containing elements with
23 repeated names can be compared using attribute or text values to determine which of the
24 candidate elements are actually comparable (fixes various feature requests / posted bugs)
25 - NEW ElementNameQualifier, ElementNameAndTextQualifier and ElementNameAndAttributeQualifier
26 classes added to provide the default (backwards compatible) and extended
27 implementions of the ElementQualifier interface
28 - NEW ComparisonController interface now used to control the operation of a
29 DifferenceEngine instance (extracted from DifferenceListener)
30 - Incorporated DifferenceConstants patch submitted by ludovicc
31 - Added support for namespaced attributes, previously missing
32 - Build file now incorporates JUnitReport
33 - Deprecated assertNotXpathsEqual() in favour of assertXpathsNotEqual() in XMLTestCase
34 - Moved assertion methods from XMLTestCase to new XMLAssert class
35 - PDF overview document added to distribution and content updated
36 - Updated Javadocs on website
37 tim.bacon@thoughtworks.com
38 November/December 2002, April 2003
39
40 Changes in version 0.8:
41 - Changes to compiled jar in distribution required for compatibility with JUnit 3.8
42 - Fixes for a defect in the DetailedDiff class that caused a
43 ClassCastException, raised by Ryan MacLachlan
44 - Small API changes for usability (e.g. allow use of Source constructor arguments
45 for Diff and Transform)
46 tim.bacon@thoughtworks.com
47 September 2002
48
49 Changes in version 0.7:
50 - DifferenceListener interface extended to allow more user control over how to
51 evaluate differences between control and test XML
52 - NEW IgnoreTextAndAttributeValuesDifferenceListener class added to allow
53 difference evaluation solely on the basis of tag and attribute names (ignoring
54 differences between text and attribute values completely)
55 - Fixes for a defect in the DetailedDiff class that caused a
56 NullPointerException, raised by eBernhard and bob
57 - Additional methods assertXpathExists and assertNotXpathExists added to
58 XMLTestCase class
59 - Additional methods added to Transform class to complete wrapping of
60 javax.xml.Transformer class, requested by tCantegrel
61 tim.bacon@thoughtworks.com
62 August 2002
63
64 Changes in version 0.6
65 - NEW DetailedDiff class to extract all the differences between two pieces of XML
66 - NEW HTMLDocumentBuilder and TolerantSaxDocumentBuilder classes added to enable
67 XML assertions to be made against badly formed HTML documents (uses the Swing
68 html parser)
69 - toString() method to return identity and description added to Difference class
70 - assertXMLEqual and assertXMLNotEqual with (Document, Document) arguments added
71 to XMLTestCase
72 - XMLTestCase now implements the XSLTConstants (and by implication the
73 XMLConstants interface)
74 - Fixes for defects raised by danny zapata (handling namespaces), aakture (handling
75 redundant whitespace in XMLUnit.getIgnoreWhitespace), and Craeg strong
76 (handling nested XSL include/import in Transform)
77 Thanks for the feedack guys!
78 timBacon@primeEight.co.uk
79 June 2002
80
81 Changes in version 0.5:
82 - NEW assertion methods in XMLTestCase: assertXMLEqual, assertXMLNotEqual,
83 assertXpathsEqual, assertXpathsNotEqual,
84 assertXpathValuesEqual, assertXpathValuesNotEqual, assertXpathEvaluatesTo,
85 assertXMLValid, assertXMLIdentical, assertNodeTestPasses
86 - NEW DifferenceEngine and Difference classes used by the Diff class to
87 facilitate comparison across multiple namespaces and for more node types
88 (DocumentType, Comment, CDATASection, and ProcessingInstruction
89 as well as Element, Attribute and Text)
90 - Diff messages now more descriptive
91 - NEW SimpleXpathEngine class for testing Xpath expressions
92 - NEW SimpleSerializer class
93 - TransformerFactory setter and getter, and utility buildDocument() methods
94 added to XMLUnit class
95 - 'global' but non-static methods in XMLTestCase deprecated (XMLUnit static
96 methods should be used instead)
97 - Xalan and Xerces specified as default JAXP implementations in the 'test'
98 target of the ant build file (to get around limitations in the Crimson parser)
99 timBacon@primeEight.co.uk
100 April 2002
101
102 Features added in version 0.4:
103 - NEW Validator class for validation against DTDs
104 - NEW NodeTest class, NodeTester interface, AbstractNodeTester and
105 CountingNodeTester classes for validating individual Nodes in a DOM tree
106 (NB: requires support for DOM Traversal in your DOM implementation)
107 - cleaner separation of source and test code through directory structure
108 - better documentation
109 - replacement of all deprecated JUnit assert() with assertEquals() calls
110 timBacon@primeEight.co.uk
111 March 2002
112
113 Features added in version 0.3:
114 - NEW Transform class added to support for JAXP/Trax compliant XSLT engines
115 - Diff class extended to support Transform class
116 - more testcases added
117 - removed external dependency on JDOM
118 timBacon@primeEight.co.uk
119 October 2001
120
121 Original source:
122 - Diff class to describe differences between DOM documents
123 - XMLUnit class to act as a Diff factory
124 - XMLTestCase extension to JUnit TestCase
125 jeff@customMonkey.org
126 April 2001
127
0 <?xml version="1.0"?>
1 <!--
2 Copyright (c) 2001-2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 -->
33 <project name="xmlunit" default="test" basedir=".">
34
35 <!-- allow properties to be overridden in a properties file -->
36 <property file="build.properties"/>
37
38 <!-- Version -->
39 <property name="xmlunit.version" value="1.6"/>
40
41 <!-- some locations -->
42 <property name="src.dir" value="src"/>
43 <property name="test.dir" value="tests"/>
44 <property name="build.dir" location="build"/>
45 <property name="lib.dir" value="${build.dir}/lib"/>
46 <property name="out.dir" value="${build.dir}/classes"/>
47 <property name="test.out.dir" value="${build.dir}/test-classes"/>
48 <property name="userguide.out.dir" value="${build.dir}/ug-classes"/>
49 <property name="test.report.dir" value="${build.dir}/test-report"/>
50 <property name="dist.dir" value="${build.dir}/dist"/>
51 <property name="docs.dir" value="${build.dir}/doc"/>
52 <property name="userguide.docs.dir" value="${docs.dir}/userguide"/>
53
54 <!-- javac properties -->
55 <property name="javac.source" value="1.3"/>
56 <property name="javac.target" value="1.3"/>
57 <property name="javac.debug" value="true"/>
58
59 <!-- junit task properties -->
60 <property name="junit.fork" value="yes"/>
61
62 <!-- some library paths -->
63 <!-- where is JAXP? property name="${xmlxsl.lib}" location="."/ -->
64 <!-- where is JUnit? property name="${junit.lib}" location="."/ -->
65
66 <!-- Docbook related properties, macros and targets -->
67 <import file="docbook.xml"/>
68
69 <target name="-props">
70 <available property="jaxp13+" classname="javax.xml.xpath.XPath"/>
71 <condition property="jaxp13+.impl">
72 <and>
73 <isset property="jaxp13+"/>
74 <available classname="java.net.Proxy"/>
75 </and>
76 </condition>
77 <available property="regexp.present" classname="java.util.regex.Matcher"/>
78 </target>
79
80 <target name="-init" depends="-props">
81 <mkdir dir="${lib.dir}"/>
82 <mkdir dir="${out.dir}"/>
83 <mkdir dir="${test.out.dir}"/>
84 <mkdir dir="${test.report.dir}"/>
85 <mkdir dir="${dist.dir}"/>
86 <mkdir dir="${docs.dir}"/>
87 <mkdir dir="${userguide.docs.dir}"/>
88 </target>
89
90 <target name="clean"
91 description="removes created directories">
92 <delete includeEmptyDirs="true" quiet="true">
93 <fileset dir="${lib.dir}"/>
94 <fileset dir="${out.dir}"/>
95 <fileset dir="${test.out.dir}"/>
96 <fileset dir="${test.report.dir}"/>
97 <fileset dir="${dist.dir}"/>
98 <fileset dir="${docs.dir}"/>
99 <fileset dir="${userguide.docs.dir}"/>
100 <fileset dir="${build.dir}"/>
101 </delete>
102 </target>
103
104 <target name="compile" depends="-init"
105 description="compiles sources and tests">
106 <javac srcdir="${src.dir}/java" destdir="${out.dir}"
107 debug="${javac.debug}" target="${javac.target}" source="${javac.source}">
108 <classpath>
109 <pathelement location="${xmlxsl.lib}"/>
110 <pathelement location="${junit.lib}"/>
111 <pathelement path="${java.class.path}"/>
112 </classpath>
113 <exclude name="**/jaxp13/**" unless="jaxp13+"/>
114 <exclude name="**/*XPathRegexAssert.java" unless="regexp.present"/>
115 </javac>
116 <javac srcdir="${test.dir}/java" destdir="${test.out.dir}"
117 debug="${javac.debug}" target="${javac.target}" source="${javac.source}">
118 <classpath>
119 <pathelement location="${out.dir}"/>
120 <pathelement location="${xmlxsl.lib}"/>
121 <pathelement location="${junit.lib}"/>
122 <pathelement path="${java.class.path}"/>
123 </classpath>
124 <exclude name="**/jaxp13/**" unless="jaxp13+"/>
125 <exclude name="**/*XPathRegexAssert.java" unless="regexp.present"/>
126 </javac>
127 </target>
128
129 <target name="test" depends="compile"
130 description="runs the tests">
131 <junit printsummary="yes" haltonfailure="no" fork="${junit.fork}"
132 forkMode="perBatch" failureproperty="tests.failed">
133 <sysproperty key="basedir" value="${basedir}"/>
134 <sysproperty key="user.dir" value="${basedir}"/>
135 <!--
136 <sysproperty key="javax.xml.parsers.DocumentBuilderFactory"
137 value="org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"/>
138 <sysproperty key="javax.xml.parsers.SAXParserFactory"
139 value="org.apache.xerces.jaxp.SAXParserFactoryImpl"/>
140 <sysproperty key="javax.xml.transform.TransformerFactory"
141 value="org.apache.xalan.processor.TransformerFactoryImpl"/>
142 -->
143 <classpath>
144 <pathelement location="${out.dir}"/>
145 <pathelement location="${test.out.dir}"/>
146 <pathelement location="${xmlxsl.lib}"/>
147 <pathelement location="${junit.lib}"/>
148 <pathelement path="${java.class.path}"/>
149 </classpath>
150 <formatter type="xml"/>
151 <batchtest todir="${test.report.dir}">
152 <fileset dir="${test.dir}/java">
153 <include name="**/test_*.java"/>
154 <exclude name="**/jaxp13/**" unless="jaxp13+.impl"/>
155 </fileset>
156 </batchtest>
157 </junit>
158
159 <junitreport todir="${test.report.dir}">
160 <fileset dir="${test.report.dir}">
161 <include name="TEST-*.xml"/>
162 </fileset>
163 <report format="frames" todir="${test.report.dir}/html"/>
164 </junitreport>
165
166 <fail if="tests.failed">Some tests failed</fail>
167 </target>
168
169 <target name="docs"
170 depends="create-users-guide,javadocs,-site"
171 description="creates the documentation bundle"/>
172
173 <target name="javadocs" depends="-init"
174 description="creates the API documentation">
175 <delete includeEmptyDirs="true" dir="${docs.dir}/api"/>
176 <javadoc destdir="${docs.dir}/api"
177 overview="${src.dir}/java/overview.html"
178 windowtitle="XMLUnit Documentation"
179 footer="&lt;p&gt;&lt;a href=&quot;http://xmlunit.sourceforge.net/&quot;&gt;XMLUnit&lt;/a&gt; is hosted by sourceforge.net&lt;/p&gt;">
180 <group title="XMLUnit v${xmlunit.version}"
181 packages="org.custommonkey.xmlunit*"/>
182 <fileset dir="${src.dir}/java">
183 <include name="org/custommonkey/**/*.java"/>
184 </fileset>
185 <classpath>
186 <fileset dir="${lib.dir}">
187 <include name="*.jar"/>
188 </fileset>
189 <pathelement path="${java.class.path}"/>
190 </classpath>
191 </javadoc>
192 </target>
193
194 <target name="-site" depends="-init">
195 <copy todir="${docs.dir}">
196 <fileset dir="${src.dir}/site">
197 <include name="*.html"/>
198 <include name="*.png"/>
199 </fileset>
200 </copy>
201 </target>
202
203 <target name="jar" depends="compile"
204 description="creates jar, Maven2 POM and Ivy file">
205 <jar jarfile="${lib.dir}/xmlunit-${xmlunit.version}.jar"
206 basedir="${out.dir}"
207 />
208
209 <tstamp>
210 <format property="ivy.publication.datetime" pattern="yyyyMMddHHmmss"/>
211 </tstamp>
212
213 <copy todir="${lib.dir}">
214 <fileset dir="${src.dir}/etc">
215 <include name="xmlunit.pom"/>
216 <include name="xmlunit-ivy.xml"/>
217 </fileset>
218 <mapper type="glob" from="xmlunit*" to="xmlunit-${xmlunit.version}*"/>
219 <filterset>
220 <filter token="VERSION" value="${xmlunit.version}"/>
221 <filter token="DATE" value="${ivy.publication.datetime}"/>
222 <filter token="DESCRIPTION" value="XMLUnit compares a control XML document to a test document or the result of a transformation, validates documents, and compares the results of XPath expressions."/>
223 <filter token="LICENSE" value="BSD License"/>
224 <filter token="LICENSE_URL" value="https://sourceforge.net/p/xmlunit/code/HEAD/tree/trunk/LICENSE.txt"/>
225 <filter token="GROUP" value="xmlunit"/>
226 <filter token="ARTIFACT" value="xmlunit"/>
227 <filter token="TYPE" value="jar"/>
228 </filterset>
229 </copy>
230 </target>
231
232 <target name="Gump" depends="test,jar"/>
233
234 <target name="bindist" depends="jar,test,docs">
235 <zip zipfile="${dist.dir}/xmlunit-${xmlunit.version}-bin.zip">
236 <zipfileset prefix="xmlunit-${xmlunit.version}/lib"
237 dir="${lib.dir}"/>
238 <zipfileset prefix="xmlunit-${xmlunit.version}/docs"
239 dir="${docs.dir}"/>
240 <zipfileset prefix="xmlunit-${xmlunit.version}" dir=".">
241 <include name="KEYS"/>
242 <include name="LICENSE.txt"/>
243 <include name="README.txt"/>
244 </zipfileset>
245 </zip>
246 </target>
247
248 <target name="srcdist" depends="-init,create-users-guide">
249 <zip zipfile="${dist.dir}/xmlunit-${xmlunit.version}-src.zip">
250 <zipfileset prefix="xmlunit-${xmlunit.version}" dir=".">
251 <include name="*.xml"/>
252 <include name="${src.dir}/"/>
253 <include name="${test.dir}/"/>
254 <include name="KEYS"/>
255 <include name="LICENSE.txt"/>
256 <include name="README.txt"/>
257 <exclude name="**/csharp/**"/>
258 </zipfileset>
259 <zipfileset dir="${userguide.docs.dir}"
260 prefix="xmlunit-${xmlunit.version}/userguide"/>
261 </zip>
262 </target>
263
264 <target name="dist"
265 depends="bindist,srcdist,compile-userguide-examples"
266 description="creates the distribution files">
267 <jar jarfile="${lib.dir}/xmlunit-${xmlunit.version}-sources.jar"
268 basedir="${src.dir}/java"
269 />
270 <jar jarfile="${lib.dir}/xmlunit-${xmlunit.version}-javadoc.jar"
271 basedir="${docs.dir}/api"
272 />
273 <checksum algorithm="md5">
274 <fileset dir="${dist.dir}">
275 <include name="*.zip"/>
276 </fileset>
277 </checksum>
278 <checksum algorithm="sha1">
279 <fileset dir="${dist.dir}">
280 <include name="*.zip"/>
281 </fileset>
282 </checksum>
283 <checksum algorithm="md5">
284 <fileset dir="${lib.dir}"/>
285 </checksum>
286 <checksum algorithm="sha1">
287 <fileset dir="${lib.dir}">
288 <exclude name="*.md5"/>
289 </fileset>
290 </checksum>
291 </target>
292
293 <target name="compile-userguide-examples" depends="compile">
294 <mkdir dir="${userguide.out.dir}"/>
295 <javac srcdir="src/user-guide" includes="org/"
296 destdir="${userguide.out.dir}" source="1.3" target="1.2">
297 <classpath>
298 <pathelement location="${junit.lib}"/>
299 <pathelement location="${out.dir}"/>
300 </classpath>
301 </javac>
302 <delete dir="${userguide.out.dir}"/>
303 </target>
304 </project>
0 <!--
1 Copyright (c) 2001-2013, Jeff Martin, Tim Bacon
2 All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14 * Neither the name of the xmlunit.sourceforge.net nor the names
15 of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written
17 permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31 -->
32 <project>
33 <!-- allow overrides -->
34 <property file="docbook.properties"/>
35
36 <!-- location of Docbook Stylesheets and dblatex -->
37 <property name="db5.xsl" location="../../docbook/docbook5-xsl-1.72.0"/>
38 <property name="dblatex" value="/usr/bin/dblatex"/>
39 <property name="xsltproc" value="/usr/bin/xsltproc"/>
40
41 <property name="html.dir" location="${userguide.docs.dir}/html"/>
42 <property name="user.guide" value="XMLUnit-Java"/>
43 <property name="src.userguide.dir" value="${src.dir}/user-guide"/>
44
45 <target name="create-users-guide"
46 depends="users-guide-html,users-guide-pdf"
47 description="creates PDF and HTML version of User's Guide"/>
48
49 <target name="-html-needs-refresh?">
50 <uptodate property="HTML is up-to-date"
51 srcfile="${src.userguide.dir}/${user.guide}.xml"
52 targetfile="${html.dir}/index.html"/>
53 </target>
54
55 <target name="-xsltproc-available?" depends="-html-needs-refresh?">
56 <available property="xsltproc available"
57 file="${xsltproc}"/>
58 <condition property="run TraX">
59 <not>
60 <or>
61 <isset property="xsltproc available"/>
62 <isset property="HTML is up-to-date"/>
63 </or>
64 </not>
65 </condition>
66 <condition property="run xsltproc">
67 <and>
68 <isset property="xsltproc available"/>
69 <not>
70 <isset property="HTML is up-to-date"/>
71 </not>
72 </and>
73 </condition>
74 </target>
75
76 <target name="-users-guide-html-pre" depends="-html-needs-refresh?"
77 unless="HTML is up-to-date">
78 <delete dir="${html.dir}" quiet="true"/>
79 <mkdir dir="${html.dir}"/>
80 </target>
81
82 <target name="-users-guide-html-trax"
83 depends="-xsltproc-available?,-users-guide-html-pre"
84 if="run TraX">
85 <xslt
86 basedir="${src.userguide.dir}"
87 destdir="${html.dir}"
88 style="${db5.xsl}/html/chunk.xsl">
89 <include name="${user.guide}.xml"/>
90
91 <param name="section.autolabel" expression="1"/>
92 <param name="section.label.includes.component.label" expression="1"/>
93 </xslt>
94 <delete file="${html.dir}/${user.guide}.html" quiet="true"/>
95 </target>
96
97 <target name="-users-guide-html-xsltproc"
98 depends="-xsltproc-available?,-users-guide-html-pre"
99 if="run xsltproc">
100 <exec executable="${xsltproc}" failonerror="true">
101 <arg value="-o"/>
102 <!-- xsltproc needs the trailing slash to work properly -->
103 <arg value="${html.dir}/"/>
104 <arg value="--param"/>
105 <arg value="section.autolabel"/>
106 <arg value="1"/>
107 <arg value="--param"/>
108 <arg value="section.label.includes.component.label"/>
109 <arg value="1"/>
110 <arg file="${db5.xsl}/html/chunk.xsl"/>
111 <arg file="${src.userguide.dir}/${user.guide}.xml"/>
112 </exec>
113 </target>
114
115 <target name="users-guide-html"
116 depends="-users-guide-html-trax,-users-guide-html-xsltproc"
117 unless="HTML is up-to-date"
118 description="Creates HTML version of the User's Guide">
119 </target>
120
121 <target name="-check-os">
122 <condition property="isWindows">
123 <os family="windows"/>
124 </condition>
125 </target>
126
127 <target name="-define-dblatex-unix" unless="isWindows"
128 depends="-check-os">
129 <macrodef name="dblatex">
130 <attribute name="sourcefile"/>
131 <sequential>
132 <apply executable="${dblatex}">
133 <fileset file="@{sourcefile}"/>
134 <globmapper from="*.xml" to="*.pdf"/>
135 </apply>
136 </sequential>
137 </macrodef>
138 </target>
139
140 <target name="-define-dblatex-cygwin" if="isWindows"
141 depends="-check-os">
142 <macrodef name="dblatex">
143 <attribute name="sourcefile"/>
144 <sequential>
145 <apply executable="bash.exe" addsourcefile="false">
146 <fileset file="@{sourcefile}"/>
147 <globmapper from="*.xml" to="*.pdf"/>
148 <arg value="-c"/>
149 <arg value="${dblatex} @{sourcefile}"/>
150 </apply>
151 </sequential>
152 </macrodef>
153 </target>
154
155 <target name="-define-dblatex"
156 depends="-define-dblatex-unix,-define-dblatex-cygwin"/>
157
158 <target name="users-guide-pdf" depends="-define-dblatex"
159 description="Creates the PDF version of the User's Guide">
160 <dblatex sourcefile="${src.userguide.dir}/${user.guide}.xml"/>
161 <move file="${src.userguide.dir}/${user.guide}.pdf"
162 todir="${userguide.docs.dir}"/>
163 </target>
164 </project>
0 <?xml version="1.0"?>
1 <!--
2 Copyright (c) 2007-2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 -->
33 <ivy-module version="1.3">
34 <info organisation="@GROUP@"
35 module="@ARTIFACT@"
36 revision="@VERSION@"
37 publication="@DATE@">
38 <license name="@LICENSE@"
39 url="@LICENSE_URL@"/>
40 <description homepage="http://www.xmlunit.org/">@DESCRIPTION@</description>
41 </info>
42 <publications>
43 <artifact name="@ARTIFACT@" type="@TYPE@"/>
44 </publications>
45 </ivy-module>
0 <?xml version="1.0"?>
1 <!--
2 Copyright (c) 2007-2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 -->
33
34 <!--
35
36 This POM is not usable as means to build XMLUnit with Maven2, it is
37 a minimal POM to allow XMLUnit's artifacts to be added to a Maven
38 repository.
39
40 -->
41 <project>
42 <modelVersion>4.0.0</modelVersion>
43 <groupId>@GROUP@</groupId>
44 <artifactId>@ARTIFACT@</artifactId>
45 <packaging>@TYPE@</packaging>
46 <name>XMLUnit for Java</name>
47 <version>@VERSION@</version>
48 <url>http://www.xmlunit.org/</url>
49 <description>@DESCRIPTION@</description>
50 <licenses>
51 <license>
52 <name>@LICENSE@</name>
53 <url>@LICENSE_URL@</url>
54 </license>
55 </licenses>
56 <scm>
57 <url>https://sourceforge.net/p/xmlunit/code/HEAD/tree/trunk/</url>
58 <connection>scm:svn:https://svn.code.sf.net/p/xmlunit/code/trunk</connection>
59 </scm>
60 <dependencies>
61 <dependency>
62 <groupId>junit</groupId>
63 <artifactId>junit</artifactId>
64 <version>3.8.2</version>
65 <optional>true</optional>
66 </dependency>
67 </dependencies>
68 <!-- Personally I'm not fond of the developers section but Sonatype's OSSRH
69 requires it -->
70 <developers>
71 <developer>
72 <id>bodewig</id>
73 <name>Stefan Bodewig</name>
74 <email>stefan.bodewig@freenet dot de</email>
75 </developer>
76 </developers>
77 </project>
0 %define name xmlunit
1 %define version 1.0
2 %define release 1
3 %define javadir %{_datadir}/java
4 %define javadocdir %{_datadir}/javadoc
5 %define section free
6
7 Name: %{name}
8 Version: %{version}
9 Release: %{release}
10 Summary: XML testing package
11 License: BSD Style Software License
12 URL: http://xmlunit.sf.net/
13 Group: Development/Testing
14 Vendor: XMLUnit Project
15 Distribution: XMLUnit
16 Source0: http://xmlunit.sf.net/dist/%{name}-%{version}-src.tgz
17 Provides: xmlunit
18 Requires: junit
19 Requires: /usr/sbin/update-alternatives
20 BuildRequires: ant >= 1.5
21 BuildArch: noarch
22 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
23
24 %description
25 XMLUnit extends JUnit to simplify unit testing of XML. It compares a control XML document to a test document or the result of a transformation, validates documents against a DTD, and (from v0.5) compares the results of XPath expressions.
26
27 %prep
28 %setup -q -n xmlunit-%{version}
29 #%patch0 -p0
30 #%patch1 -p2
31
32 %build
33
34 # build with empty CLASSPATH
35 ant -buildfile build.xml -Dbuild.compiler=modern jar docs
36
37 %install
38 rm -rf $RPM_BUILD_ROOT
39
40 # jars
41 mkdir -p $RPM_BUILD_ROOT%{javadir}
42 cp -p lib/%{name}-%{version}.jar $RPM_BUILD_ROOT%{javadir}/%{name}-%{version}.jar
43 (cd $RPM_BUILD_ROOT%{javadir} && for jar in *-%{version}.jar; do ln -sf ${jar} `echo $jar| sed "s|-%{version}||g"`; done)
44
45 # docs
46 #mkdir -p $RPM_BUILD_ROOT%{javadocdir}/%{name}-%{version}
47 #cp -pr doc/* \
48 #$RPM_BUILD_ROOT%{javadocdir}/%{name}-%{version}
49
50 %clean
51 rm -rf $RPM_BUILD_ROOT
52
53 %post
54
55 %postun
56
57 %files
58 %defattr(0644,root,root,0755)
59 %doc LICENSE.txt README.txt ISSUES
60 %{javadir}/*
61 #%{javadocdir}/*
62
63 %changelog
64 * Wed Mar 05 2003 Jeff Martin <jeff@custommonkey.org> 1.0.0-1jpp
65 - first release
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Attr;
39 import org.w3c.dom.CDATASection;
40 import org.w3c.dom.Comment;
41 import org.w3c.dom.DocumentType;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.Entity;
44 import org.w3c.dom.EntityReference;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.Notation;
47 import org.w3c.dom.ProcessingInstruction;
48 import org.w3c.dom.Text;
49
50 /**
51 * Helper class.
52 * Abstract interface implementation that performs Node-type checks and
53 * delegates testNode() processing to subclass.
54 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
55 * @see NodeTest
56 */
57 public abstract class AbstractNodeTester implements NodeTester {
58 /**
59 * Validate a single Node by delegating to node type specific methods.
60 * @see #testAttribute(Attr)
61 * @see #testCDATASection(CDATASection)
62 * @see #testComment(Comment)
63 * @see #testDocumentType(DocumentType)
64 * @see #testElement(Element)
65 * @see #testEntity(Entity)
66 * @see #testEntityReference(EntityReference)
67 * @see #testNotation(Notation)
68 * @see #testProcessingInstruction(ProcessingInstruction)
69 * @see #testText(Text)
70 */
71 public void testNode(Node aNode, NodeTest forTest) throws NodeTestException {
72 switch (aNode.getNodeType()) {
73 case Node.ATTRIBUTE_NODE:
74 // should not happen as attributes are not exposed by DOM traversal
75 testAttribute((Attr)aNode);
76 break;
77 case Node.CDATA_SECTION_NODE:
78 testCDATASection((CDATASection)aNode);
79 break;
80 case Node.COMMENT_NODE:
81 testComment((Comment)aNode);
82 break;
83 case Node.DOCUMENT_TYPE_NODE:
84 testDocumentType((DocumentType)aNode);
85 break;
86 case Node.ELEMENT_NODE:
87 testElement((Element)aNode);
88 break;
89 case Node.ENTITY_NODE:
90 testEntity((Entity)aNode);
91 break;
92 case Node.ENTITY_REFERENCE_NODE:
93 testEntityReference((EntityReference)aNode);
94 break;
95 case Node.NOTATION_NODE:
96 testNotation((Notation)aNode);
97 break;
98 case Node.PROCESSING_INSTRUCTION_NODE:
99 testProcessingInstruction(
100 (ProcessingInstruction) aNode);
101 break;
102 case Node.TEXT_NODE:
103 testText((Text)aNode);
104 break;
105 default:
106 throw new NodeTestException("No delegate method for Node type",
107 aNode);
108 }
109 }
110
111 /**
112 * Template delegator for testNode() method. OVERRIDE to add custom logic
113 * @param attribute
114 * @exception NodeTestException always: override if required in subclass
115 */
116 public void testAttribute(Attr attribute) throws NodeTestException {
117 unhandled(attribute);
118 }
119 /**
120 * Template delegator for testNode() method. OVERRIDE to add custom logic
121 * @param cdata
122 * @exception NodeTestException always: override if required in subclass
123 */
124 public void testCDATASection(CDATASection cdata) throws NodeTestException {
125 unhandled(cdata);
126 }
127 /**
128 * Template delegator for testNode() method. OVERRIDE to add custom logic
129 * @param comment
130 * @exception NodeTestException always: override if required in subclass
131 */
132 public void testComment(Comment comment) throws NodeTestException {
133 unhandled(comment);
134 }
135 /**
136 * Template delegator for testNode() method. OVERRIDE to add custom logic
137 * @param doctype
138 * @exception NodeTestException always: override if required in subclass
139 */
140 public void testDocumentType(DocumentType doctype) throws NodeTestException {
141 unhandled(doctype);
142 }
143 /**
144 * Template delegator for testNode() method. OVERRIDE to add custom logic
145 * @param element
146 * @exception NodeTestException always: override if required in subclass
147 */
148 public void testElement(Element element) throws NodeTestException {
149 unhandled(element);
150 }
151 /**
152 * Template delegator for testNode() method. OVERRIDE to add custom logic
153 * @param entity
154 * @exception NodeTestException always: override if required in subclass
155 */
156 public void testEntity(Entity entity) throws NodeTestException {
157 unhandled(entity);
158 }
159 /**
160 * Template delegator for testNode() method. OVERRIDE to add custom logic
161 * @param reference
162 * @exception NodeTestException always: override if required in subclass
163 */
164 public void testEntityReference(EntityReference reference) throws NodeTestException {
165 unhandled(reference);
166 }
167 /**
168 * Template delegator for testNode() method. OVERRIDE to add custom logic
169 * @param notation
170 * @exception NodeTestException always: override if required in subclass
171 */
172 public void testNotation(Notation notation) throws NodeTestException {
173 unhandled(notation);
174 }
175 /**
176 * Template delegator for testNode() method. OVERRIDE to add custom logic
177 * @param instr
178 * @exception NodeTestException always: override if required in subclass
179 */
180 public void testProcessingInstruction(ProcessingInstruction instr) throws NodeTestException {
181 unhandled(instr);
182 }
183 /**
184 * Template delegator for testNode() method. OVERRIDE to add custom logic
185 * @param text
186 * @exception NodeTestException always: override if required in subclass
187 */
188 public void testText(Text text) throws NodeTestException {
189 unhandled(text);
190 }
191
192 private void unhandled(Node aNode) throws NodeTestException {
193 throw new NodeTestException("Test fails by default in AbstractNodeTester", aNode);
194 }
195
196 /**
197 * Validate that the Nodes validated one-by-one in the <code>isValid</code>
198 * method were all the Nodes expected. By default do nothing:
199 * can override to add custom logic
200 * @exception NodeTestException if mode Nodes were expected
201 */
202 public void noMoreNodes(NodeTest forTest) throws NodeTestException {
203 //by default do nothing
204 }
205 }
206
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit;
36
37 /**
38 * Callback interface used by DifferenceEngine to determine whether to halt the
39 * node-by-node comparison of two pieces of XML
40 */
41 public interface ComparisonController {
42 /**
43 * Determine whether a Difference that the listener has been notified of
44 * should halt further XML comparison. Default behaviour for a Diff
45 * instance is to halt if the Difference is not recoverable.
46 * @see Difference#isRecoverable
47 * @param afterDifference the last Difference passed to <code>differenceFound</code>
48 * @return true to halt further comparison, false otherwise
49 */
50 boolean haltComparison(Difference afterDifference);
51
52 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * Counts the number of nodes in a document to allow assertions to be made
40 * using a NodeTest.
41 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
42 * @see NodeTest
43 * @deprecated Use {@link
44 * org.custommonkey.xmlunit.examples.CountingNodeTester
45 * CountingNodeTester} instead.
46 */
47 public class CountingNodeTester
48 extends org.custommonkey.xmlunit.examples.CountingNodeTester {
49
50 public CountingNodeTester(int expectedNumNodes) {
51 super(expectedNumNodes);
52 }
53 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.List;
39 import java.util.ArrayList;
40
41 /**
42 * Compares and describes all the differences between two XML documents.
43 * The document comparison does not stop once the first unrecoverable difference
44 * is found, unlike the Diff class.
45 * Note that because the differences are described relative to some control XML
46 * the list of all differences when <i>A</i> is compared to <i>B</i> will not
47 * necessarily be the same as when <i>B</i> is compared to <i>A</i>.
48 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
49 */
50 public class DetailedDiff extends Diff {
51 private final List allDifferences;
52
53 /**
54 * Create a new instance based on a prototypical Diff instance
55 * @param prototype the Diff instance for which more detailed difference
56 * information is required
57 */
58 public DetailedDiff(Diff prototype) {
59 super(prototype);
60 allDifferences = new ArrayList();
61 }
62
63 /**
64 * DifferenceListener implementation.
65 * Add the difference to the list of all differences
66 * @param expected
67 * @param actual
68 * @param control
69 * @param test
70 * @param comparingWhat
71 * @return the value supplied by the superclass implementation
72 */
73 public int differenceFound(Difference difference) {
74 final int returnValue = super.differenceFound(difference);
75 switch (returnValue) {
76 case RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL:
77 return returnValue;
78 case RETURN_ACCEPT_DIFFERENCE:
79 break;
80 case RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR:
81 difference.setRecoverable(true);
82 break;
83 case RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT:
84 difference.setRecoverable(false);
85 break;
86 default:
87 throw new IllegalArgumentException(returnValue
88 + " is not a defined "
89 + " DifferenceListener"
90 + ".RETURN_... value");
91 }
92 allDifferences.add(difference);
93 return returnValue;
94 }
95
96 /**
97 * ComparisonController implementation.
98 * @param afterDifference
99 * @return false always as this class wants to see all differences
100 */
101 public boolean haltComparison(Difference afterDifference) {
102 return false;
103 }
104
105 /**
106 * Obtain all the differences found by this instance
107 * @return a list of {@link Difference differences}
108 */
109 public List getAllDifferences() {
110 compare();
111 return allDifferences;
112 }
113 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008,2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39 import java.io.Reader;
40 import java.io.StringReader;
41 import javax.xml.transform.TransformerException;
42 import javax.xml.transform.dom.DOMSource;
43
44 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
45
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Node;
48 import org.xml.sax.InputSource;
49 import org.xml.sax.SAXException;
50
51 /**
52 * Compares and describes any difference between XML documents.
53 * Two documents are either:
54 * <br /><ul>
55 * <li><i>identical</i>: the content and sequence of the nodes in the documents
56 * are exactly the same</li>
57 * <li><i>similar</i>: the content of the nodes in the documents are the same,
58 * but minor differences exist e.g. sequencing of sibling elements, values of
59 * namespace prefixes, use of implied attribute values</li>
60 * <li><i>different</i>: the contents of the documents are fundamentally
61 * different</li>
62 * </ul>
63 * <br />
64 * The difference between compared documents is contained in a message buffer
65 * held in this class, accessible either through the <code>appendMessage</code>
66 * or <code>toString</code> methods. NB: When comparing documents, the
67 * comparison is halted as soon as the status (identical / similar / different)
68 * is known with certainty. For a list of all differences between the documents
69 * an instance of {@link DetailedDiff the DetailedDiff class} can be used
70 * instead.
71 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
72 */
73 public class Diff
74 implements DifferenceListener, ComparisonController {
75 private final Document controlDoc;
76 private final Document testDoc;
77 private boolean similar = true;
78 private boolean identical = true;
79 private boolean compared = false;
80 private boolean haltComparison = false;
81 private StringBuffer messages;
82 private DifferenceEngine differenceEngine;
83 private DifferenceListener differenceListenerDelegate;
84 private ElementQualifier elementQualifierDelegate;
85 private MatchTracker matchTrackerDelegate;
86
87 /**
88 * Construct a Diff that compares the XML in two Strings
89 */
90 public Diff(String control, String test)
91 throws SAXException, IOException {
92 this(new StringReader(control), new StringReader(test));
93 }
94
95 /**
96 * Construct a Diff that compares the XML read from two Readers
97 */
98 public Diff(Reader control, Reader test)
99 throws SAXException, IOException {
100 this(XMLUnit.buildDocument(XMLUnit.newControlParser(), control),
101 XMLUnit.buildDocument(XMLUnit.newTestParser(), test));
102 }
103
104 /**
105 * Construct a Diff that compares the XML in two Documents
106 */
107 public Diff(Document controlDoc, Document testDoc) {
108 this(controlDoc, testDoc, (DifferenceEngine) null);
109 }
110
111 /**
112 * Construct a Diff that compares the XML in a control Document against the
113 * result of a transformation
114 */
115 public Diff(String control, Transform testTransform)
116 throws IOException, TransformerException, SAXException {
117 this(XMLUnit.buildControlDocument(control),
118 testTransform.getResultDocument());
119 }
120
121 /**
122 * Construct a Diff that compares the XML read from two JAXP InputSources
123 */
124 public Diff(InputSource control, InputSource test)
125 throws SAXException, IOException {
126 this(XMLUnit.buildDocument(XMLUnit.newControlParser(), control),
127 XMLUnit.buildDocument(XMLUnit.newTestParser(), test));
128 }
129
130 /**
131 * Construct a Diff that compares the XML in two JAXP DOMSources
132 */
133 public Diff(DOMSource control, DOMSource test) {
134 this(control.getNode().getOwnerDocument(),
135 test.getNode().getOwnerDocument());
136 }
137
138 /**
139 * Construct a Diff that compares the XML in two Documents using a specific
140 * DifferenceEngine
141 */
142 public Diff(Document controlDoc, Document testDoc,
143 DifferenceEngine comparator) {
144 this(controlDoc, testDoc, comparator, new ElementNameQualifier());
145 }
146
147 /**
148 * Construct a Diff that compares the XML in two Documents using a specific
149 * DifferenceEngine and ElementQualifier
150 */
151 public Diff(Document controlDoc, Document testDoc,
152 DifferenceEngine comparator,
153 ElementQualifier elementQualifier) {
154 this.controlDoc = getManipulatedDocument(controlDoc);
155 this.testDoc = getManipulatedDocument(testDoc);
156 this.elementQualifierDelegate = elementQualifier;
157 this.differenceEngine = comparator;
158 this.messages = new StringBuffer();
159 }
160
161 /**
162 * Construct a Diff from a prototypical instance.
163 * Used by extension subclasses
164 * @param prototype a prototypical instance
165 */
166 protected Diff(Diff prototype) {
167 this(prototype.controlDoc, prototype.testDoc, prototype.differenceEngine,
168 prototype.elementQualifierDelegate);
169 this.differenceListenerDelegate = prototype.differenceListenerDelegate;
170 }
171
172 /**
173 * If {@link XMLUnit#getIgnoreWhitespace whitespace is ignored} in
174 * differences then manipulate the content to strip the redundant
175 * whitespace
176 * @param originalDoc a document making up one half of this difference
177 * @return the original document with redundant whitespace removed if
178 * differences ignore whitespace
179 */
180 private Document getWhitespaceManipulatedDocument(Document originalDoc) {
181 return XMLUnit.getIgnoreWhitespace()
182 ? XMLUnit.getWhitespaceStrippedDocument(originalDoc)
183 : originalDoc;
184 }
185
186 /**
187 * Manipulates the given document according to the setting in the
188 * XMLUnit class.
189 *
190 * <p>This may involve:</p>
191 * <ul>
192 * <li>{@link XMLUnit.setIgnoreWhitespace stripping redundant
193 * whitespace}</li>
194 * <li>{@link XMLUnit.setIgnoreComments stripping comments}</li>
195 * <li>{@link XMLUnit.setNormalize normalizing Text nodes}</li>
196 * </ul>
197 *
198 * @param orig a document making up one half of this difference
199 * @return manipulated doc
200 */
201 private Document getManipulatedDocument(Document orig) {
202 return getNormalizedDocument(getCommentlessDocument(getWhitespaceManipulatedDocument(orig)));
203 }
204
205 /**
206 * Removes all comment nodes if {@link XMLUnit.getIgnoreComments
207 * comments are ignored}.
208 *
209 * @param originalDoc a document making up one half of this difference
210 * @return manipulated doc
211 */
212 private Document getCommentlessDocument(Document orig) {
213 if (!XMLUnit.getIgnoreComments()) {
214 return orig;
215 }
216 try {
217 Transform commentStripper = XMLUnit.getStripCommentsTransform(orig);
218 return commentStripper.getResultDocument();
219 } catch (TransformerException e) {
220 throw new XMLUnitRuntimeException(e.getMessage(), e.getCause());
221 }
222 }
223
224 private Document getNormalizedDocument(Document orig) {
225 if (!XMLUnit.getNormalize()) {
226 return orig;
227 }
228 Document d = (Document) orig.cloneNode(true);
229 d.normalize();
230 return d;
231 }
232
233 /**
234 * Top of the recursive comparison execution tree
235 */
236 protected final void compare() {
237 if (compared) {
238 return;
239 }
240 getDifferenceEngine().compare(controlDoc, testDoc, this,
241 elementQualifierDelegate);
242 compared = true;
243 }
244
245 /**
246 * Return the result of a comparison. Two documents are considered
247 * to be "similar" if they contain the same elements and attributes
248 * regardless of order.
249 */
250 public boolean similar(){
251 compare();
252 return similar;
253 }
254
255 /**
256 * Return the result of a comparison. Two documents are considered
257 * to be "identical" if they contain the same elements and attributes
258 * in the same order.
259 */
260 public boolean identical(){
261 compare();
262 return identical;
263 }
264
265 /**
266 * Append a meaningful message to the buffer of messages
267 * @param appendTo the messages buffer
268 * @param expected
269 * @param actual
270 * @param control
271 * @param test
272 * @param difference
273 */
274 private void appendDifference(StringBuffer appendTo, Difference difference) {
275 appendTo.append(' ').append(difference).append('\n');
276 }
277
278 /**
279 * DifferenceListener implementation.
280 * If the {@link Diff#overrideDifferenceListener overrideDifferenceListener}
281 * method has been called then the interpretation of the difference
282 * will be delegated.
283 * @param difference
284 * @return a DifferenceListener.RETURN_... constant indicating how the
285 * difference was interpreted.
286 * Always RETURN_ACCEPT_DIFFERENCE if the call is not delegated.
287 */
288 public int differenceFound(Difference difference) {
289 int returnValue = RETURN_ACCEPT_DIFFERENCE;
290 if (differenceListenerDelegate != null) {
291 returnValue = differenceListenerDelegate.differenceFound(difference);
292 }
293
294 switch (returnValue) {
295 case RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL:
296 return returnValue;
297 case RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR:
298 identical = false;
299 haltComparison = false;
300 break;
301 case RETURN_ACCEPT_DIFFERENCE:
302 identical = false;
303 if (difference.isRecoverable()) {
304 haltComparison = false;
305 } else {
306 similar = false;
307 haltComparison = true;
308 }
309 break;
310 case RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT:
311 identical = similar = false;
312 haltComparison = true;
313 break;
314 default:
315 throw new IllegalArgumentException(returnValue
316 + " is not a defined DifferenceListener.RETURN_... value");
317 }
318 if (haltComparison) {
319 messages.append("\n[different]");
320 } else {
321 messages.append("\n[not identical]");
322 }
323 appendDifference(messages, difference);
324 return returnValue;
325 }
326
327 /**
328 * DifferenceListener implementation.
329 * If the {@link Diff#overrideDifferenceListener overrideDifferenceListener}
330 * method has been called then the call will be delegated
331 * otherwise a message is printed to <code>System.err</code>.
332 * @param control
333 * @param test
334 */
335 public void skippedComparison(Node control, Node test) {
336 if (differenceListenerDelegate != null) {
337 differenceListenerDelegate.skippedComparison(control, test);
338 } else {
339 System.err.println("DifferenceListener.skippedComparison: "
340 + "unhandled control node type=" + control
341 + ", unhandled test node type=" + test);
342 }
343 }
344
345 /**
346 * ComparisonController implementation.
347 * @param afterDifference
348 * @return true if the difference is not recoverable and
349 * the comparison should be halted, or false if the difference
350 * is recoverable and the comparison can continue
351 */
352 public boolean haltComparison(Difference afterDifference) {
353 return haltComparison;
354 }
355
356 /**
357 * Append the message from the result of this Diff instance to a specified
358 * StringBuffer
359 * @param toAppendTo
360 * @return specified StringBuffer with message appended
361 */
362 public StringBuffer appendMessage(StringBuffer toAppendTo) {
363 compare();
364 if (messages.length()==0) {
365 messages.append("[identical]");
366 }
367 // fix for JDK1.4 backwards incompatibility
368 return toAppendTo.append(messages.toString());
369 }
370
371 /**
372 * Get the result of this Diff instance as a String
373 *
374 * <p><b>Note:</b></p> This method will perform the comparison and
375 * cache the result if it hasn't been performed already. Any
376 * configuration changes made after calling this method will be
377 * ignored.</p>
378 *
379 * @return result of this Diff
380 */
381 public String toString(){
382 StringBuffer buf = new StringBuffer(getClass().getName());
383 appendMessage(buf);
384 return buf.toString();
385 }
386
387 /**
388 * Override the <code>DifferenceListener</code> used to determine how
389 * to handle differences that are found.
390 * @param delegate the DifferenceListener instance to delegate handling to.
391 */
392 public void overrideDifferenceListener(DifferenceListener delegate) {
393 this.differenceListenerDelegate = delegate;
394 }
395
396 /**
397 * Override the <code>ElementQualifier</code> used to determine which
398 * control and test nodes are comparable for this difference comparison.
399 * @param delegate the ElementQualifier instance to delegate to.
400 */
401 public void overrideElementQualifier(ElementQualifier delegate) {
402 this.elementQualifierDelegate = delegate;
403 }
404
405 /**
406 * Override the <code>MatchTracker</code> used to track
407 * successfully matched nodes.
408 * @param delegate the MatchTracker instance to delegate handling to.
409 */
410 public void overrideMatchTracker(MatchTracker delegate) {
411 this.matchTrackerDelegate = delegate;
412 if (differenceEngine != null) {
413 differenceEngine.setMatchTracker(delegate);
414 }
415 }
416
417 /**
418 * Lazily initializes the difference engine if it hasn't been set
419 * via a constructor.
420 */
421 private DifferenceEngine getDifferenceEngine() {
422 return differenceEngine == null
423 ? new DifferenceEngine(this, matchTrackerDelegate)
424 : differenceEngine;
425 }
426
427 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38
39 /**
40 * Value object that describes a difference between DOM Nodes using one of
41 * the DifferenceConstants ID values and a NodeDetail instance.
42 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
43 * @see NodeDetail
44 */
45 public class Difference {
46 /** Simple unique identifier */
47 private final int id;
48 /** Description of the difference */
49 private final String description;
50 /** TRUE if the difference represents a similarity, FALSE otherwise */
51 private boolean recoverable;
52
53 private NodeDetail controlNodeDetail = null;
54 private NodeDetail testNodeDetail = null;
55
56 /**
57 * Constructor for non-similar Difference instances
58 * @param id
59 * @param description
60 */
61 protected Difference(int id, String description) {
62 this(id, description, false);
63 }
64
65 /**
66 * Constructor for similar Difference instances
67 * @param id
68 * @param description
69 */
70 protected Difference(int id, String description, boolean recoverable) {
71 this.id = id;
72 this.description = description;
73 this.recoverable = recoverable;
74 }
75
76
77 /**
78 * Copy constructor using prototype Difference and
79 * encountered NodeDetails
80 */
81 protected Difference(Difference prototype, NodeDetail controlNodeDetail,
82 NodeDetail testNodeDetail) {
83 this(prototype.getId(), prototype.getDescription(), prototype.isRecoverable());
84 this.controlNodeDetail = controlNodeDetail;
85 this.testNodeDetail = testNodeDetail;
86 }
87
88 /**
89 * @return the id
90 */
91 public int getId() {
92 return id;
93 }
94
95 /**
96 * @return the description
97 */
98 public String getDescription() {
99 return description;
100 }
101
102 /**
103 * @return TRUE if the difference represents a similarity, FALSE otherwise
104 */
105 public boolean isRecoverable() {
106 return recoverable;
107 }
108
109 /**
110 * Allow the recoverable field value to be overridden.
111 * Used when an override DifferenceListener is used in conjunction with
112 * a DetailedDiff.
113 */
114 protected void setRecoverable(boolean overrideValue) {
115 recoverable = overrideValue;
116 }
117
118 /**
119 * @return the NodeDetail from the piece of XML used as the control
120 * at the Node where this difference was encountered
121 */
122 public NodeDetail getControlNodeDetail() {
123 return controlNodeDetail;
124 }
125
126 /**
127 * @return the NodeDetail from the piece of XML used as the test
128 * at the Node where this difference was encountered
129 */
130 public NodeDetail getTestNodeDetail() {
131 return testNodeDetail;
132 }
133
134 /**
135 * Now that Differences can be constructed from prototypes
136 * we need to be able to compare them to those in DifferenceConstants
137 */
138 public boolean equals(Object other) {
139 if (other == null) {
140 return false;
141 } else if (other instanceof Difference) {
142 Difference otherDifference = (Difference) other;
143 return id == otherDifference.getId();
144 } else {
145 return false;
146 }
147 }
148
149 /**
150 * hashcode implementation to go with equals.
151 */
152 public int hashCode() {
153 return id;
154 }
155
156 /**
157 * @return a basic representation of the object state and identity
158 * and if <code>NodeDetail</code> instances are populated append
159 * their details also
160 */
161 public String toString() {
162 StringBuffer buf = new StringBuffer();
163 if (controlNodeDetail == null || testNodeDetail == null) {
164 appendBasicRepresentation(buf);
165 } else {
166 appendDetailedRepresentation(buf);
167 }
168 return buf.toString();
169 }
170
171 private void appendBasicRepresentation(StringBuffer buf) {
172 buf.append("Difference (#").append(id).
173 append(") ").append(description);
174 }
175
176 private void appendDetailedRepresentation(StringBuffer buf) {
177 buf.append("Expected ").append(getDescription())
178 .append(" '").append(controlNodeDetail.getValue())
179 .append("' but was '").append(testNodeDetail.getValue())
180 .append("' - comparing ");
181 NodeDescriptor.appendNodeDetail(buf, controlNodeDetail);
182 buf.append(" to ");
183 NodeDescriptor.appendNodeDetail(buf, testNodeDetail);
184 }
185
186 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38
39 /**
40 * Constants for describing differences between DOM Nodes.
41 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
42 */
43 public interface DifferenceConstants {
44 /** Comparing an implied attribute value against an explicit value */
45 int ATTR_VALUE_EXPLICITLY_SPECIFIED_ID = 1;
46 /** Comparing 2 elements and one has an attribute the other does not */
47 int ATTR_NAME_NOT_FOUND_ID = 2;
48 /** Comparing 2 attributes with the same name but different values */
49 int ATTR_VALUE_ID = 3;
50 /** Comparing 2 attribute lists with the same attributes in different sequence */
51 int ATTR_SEQUENCE_ID = 4;
52 /** Comparing 2 CDATA sections with different values */
53 int CDATA_VALUE_ID = 5;
54 /** Comparing 2 comments with different values */
55 int COMMENT_VALUE_ID = 6;
56 /** Comparing 2 document types with different names */
57 int DOCTYPE_NAME_ID = 7;
58 /** Comparing 2 document types with different public identifiers */
59 int DOCTYPE_PUBLIC_ID_ID = 8;
60 /** Comparing 2 document types with different system identifiers */
61 int DOCTYPE_SYSTEM_ID_ID = 9;
62 /** Comparing 2 elements with different tag names */
63 int ELEMENT_TAG_NAME_ID = 10;
64 /** Comparing 2 elements with different number of attributes */
65 int ELEMENT_NUM_ATTRIBUTES_ID = 11;
66 /** Comparing 2 processing instructions with different targets */
67 int PROCESSING_INSTRUCTION_TARGET_ID = 12;
68 /** Comparing 2 processing instructions with different instructions */
69 int PROCESSING_INSTRUCTION_DATA_ID = 13;
70 /** Comparing 2 different text values */
71 int TEXT_VALUE_ID = 14;
72 /** Comparing 2 nodes with different namespace prefixes */
73 int NAMESPACE_PREFIX_ID = 15;
74 /** Comparing 2 nodes with different namespace URIs */
75 int NAMESPACE_URI_ID = 16;
76 /** Comparing 2 nodes with different node types */
77 int NODE_TYPE_ID = 17;
78 /** Comparing 2 nodes but only one has any children*/
79 int HAS_CHILD_NODES_ID = 18;
80 /** Comparing 2 nodes with different numbers of children */
81 int CHILD_NODELIST_LENGTH_ID = 19;
82 /** Comparing 2 nodes with children whose nodes are in different sequence*/
83 int CHILD_NODELIST_SEQUENCE_ID = 20;
84 /** Comparing 2 Documents only one of which has a doctype */
85 int HAS_DOCTYPE_DECLARATION_ID = 21;
86 /** Comparing 2 nodes and one holds more childnodes than can be
87 * matched against child nodes of the other. */
88 int CHILD_NODE_NOT_FOUND_ID = 22;
89 /** Comparing 2 nodes with different xsi:schemaLocation
90 * attributes, potentially only one of the two provides such an
91 * attribute at all.
92 */
93 int SCHEMA_LOCATION_ID = 23;
94 /** Comparing 2 nodes with different xsi:noNamespaceSchemaLocation
95 * attributes, potentially only one of the two provides such an
96 * attribute at all.
97 */
98 int NO_NAMESPACE_SCHEMA_LOCATION_ID = 24;
99
100 /** Comparing an implied attribute value against an explicit value */
101 public static final Difference ATTR_VALUE_EXPLICITLY_SPECIFIED =
102 new Difference(ATTR_VALUE_EXPLICITLY_SPECIFIED_ID,
103 "attribute value explicitly specified", true);
104
105 /** Comparing 2 elements and one has an attribute the other does not */
106 public static final Difference ATTR_NAME_NOT_FOUND =
107 new Difference(ATTR_NAME_NOT_FOUND_ID, "attribute name");
108
109 /** Comparing 2 attributes with the same name but different values */
110 public static final Difference ATTR_VALUE =
111 new Difference(ATTR_VALUE_ID, "attribute value");
112
113 /** Comparing 2 attribute lists with the same attributes in different sequence */
114 public static final Difference ATTR_SEQUENCE =
115 new Difference(ATTR_SEQUENCE_ID, "sequence of attributes", true);
116
117 /** Comparing 2 CDATA sections with different values */
118 public static final Difference CDATA_VALUE =
119 new Difference(CDATA_VALUE_ID, "CDATA section value");
120
121 /** Comparing 2 comments with different values */
122 public static final Difference COMMENT_VALUE =
123 new Difference(COMMENT_VALUE_ID, "comment value");
124
125 /** Comparing 2 document types with different names */
126 public static final Difference DOCTYPE_NAME =
127 new Difference(DOCTYPE_NAME_ID, "doctype name");
128
129 /** Comparing 2 document types with different public identifiers */
130 public static final Difference DOCTYPE_PUBLIC_ID =
131 new Difference(DOCTYPE_PUBLIC_ID_ID, "doctype public identifier");
132
133 /** Comparing 2 document types with different system identifiers */
134 public static final Difference DOCTYPE_SYSTEM_ID =
135 new Difference(DOCTYPE_SYSTEM_ID_ID, "doctype system identifier", true);
136
137 /** Comparing 2 elements with different tag names */
138 public static final Difference ELEMENT_TAG_NAME =
139 new Difference(ELEMENT_TAG_NAME_ID, "element tag name");
140
141 /** Comparing 2 elements with different number of attributes */
142 public static final Difference ELEMENT_NUM_ATTRIBUTES =
143 new Difference(ELEMENT_NUM_ATTRIBUTES_ID, "number of element attributes");
144
145 /** Comparing 2 processing instructions with different targets */
146 public static final Difference PROCESSING_INSTRUCTION_TARGET =
147 new Difference(PROCESSING_INSTRUCTION_TARGET_ID,
148 "processing instruction target");
149
150 /** Comparing 2 processing instructions with different instructions */
151 public static final Difference PROCESSING_INSTRUCTION_DATA =
152 new Difference(PROCESSING_INSTRUCTION_DATA_ID,
153 "processing instruction data");
154
155 /** Comparing 2 different text values */
156 public static final Difference TEXT_VALUE =
157 new Difference(TEXT_VALUE_ID, "text value");
158
159 /** Comparing 2 nodes with different namespace prefixes */
160 public static final Difference NAMESPACE_PREFIX =
161 new Difference(NAMESPACE_PREFIX_ID, "namespace prefix", true);
162
163 /** Comparing 2 nodes with different namespace URIs */
164 public static final Difference NAMESPACE_URI =
165 new Difference(NAMESPACE_URI_ID, "namespace URI");
166
167 /** Comparing 2 nodes with different node types */
168 public static final Difference NODE_TYPE =
169 new Difference(NODE_TYPE_ID, "node type");
170
171 /** Comparing 2 nodes but only one has any children*/
172 public static final Difference HAS_CHILD_NODES =
173 new Difference(HAS_CHILD_NODES_ID, "presence of child nodes to be");
174
175 /** Comparing 2 nodes with different numbers of children */
176 public static final Difference CHILD_NODELIST_LENGTH =
177 new Difference(CHILD_NODELIST_LENGTH_ID, "number of child nodes");
178
179 /** Comparing 2 nodes with children whose nodes are in different sequence*/
180 public static final Difference CHILD_NODELIST_SEQUENCE =
181 new Difference(CHILD_NODELIST_SEQUENCE_ID,
182 "sequence of child nodes", true);
183
184 /** Comparing 2 Documents only one of which has a doctype */
185 public static final Difference HAS_DOCTYPE_DECLARATION =
186 new Difference(HAS_DOCTYPE_DECLARATION_ID,
187 "presence of doctype declaration", true);
188
189 /** Comparing 2 nodes and one holds more childnodes than can be
190 * matched against child nodes of the other. */
191 public static final Difference CHILD_NODE_NOT_FOUND =
192 new Difference(CHILD_NODE_NOT_FOUND_ID, "presence of child node");
193
194 /** Comparing 2 nodes with different xsi:schemaLocation
195 * attributes, potentially only one of the two provides such an
196 * attribute at all.
197 */
198 public static final Difference SCHEMA_LOCATION =
199 new Difference(SCHEMA_LOCATION_ID, "xsi:schemaLocation attribute",
200 true);
201 /** Comparing 2 nodes with different xsi:noNamespaceSchemaLocation
202 * attributes, potentially only one of the two provides such an
203 * attribute at all.
204 */
205 public static final Difference NO_NAMESPACE_SCHEMA_LOCATION =
206 new Difference(NO_NAMESPACE_SCHEMA_LOCATION_ID,
207 "xsi:noNamespaceSchemaLocation attribute",
208 true);
209 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
42
43 import org.w3c.dom.Attr;
44 import org.w3c.dom.CharacterData;
45 import org.w3c.dom.CDATASection;
46 import org.w3c.dom.Comment;
47 import org.w3c.dom.Document;
48 import org.w3c.dom.DocumentType;
49 import org.w3c.dom.Element;
50 import org.w3c.dom.NamedNodeMap;
51 import org.w3c.dom.Node;
52 import org.w3c.dom.NodeList;
53 import org.w3c.dom.ProcessingInstruction;
54 import org.w3c.dom.Text;
55
56 /**
57 * Class that has responsibility for comparing Nodes and notifying a
58 * DifferenceListener of any differences or dissimilarities that are found.
59 * Knows how to compare namespaces and nested child nodes, but currently
60 * only compares nodes of type ELEMENT_NODE, CDATA_SECTION_NODE,
61 * COMMENT_NODE, DOCUMENT_TYPE_NODE, PROCESSING_INSTRUCTION_NODE and TEXT_NODE.
62 * Nodes of other types (eg ENTITY_NODE) will be skipped.
63 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.
64 * sourceforge.net</a>
65 * @see DifferenceListener#differenceFound(Difference)
66 */
67 public class DifferenceEngine implements DifferenceConstants {
68 private static final String NULL_NODE = "null";
69 private static final String NOT_NULL_NODE = "not null";
70 private static final String ATTRIBUTE_ABSENT = "[attribute absent]";
71 private final ComparisonController controller;
72 private MatchTracker matchTracker;
73 private final XpathNodeTracker controlTracker;
74 private final XpathNodeTracker testTracker;
75
76 /**
77 * Simple constructor that uses no MatchTracker at all.
78 * @param controller the instance used to determine whether a Difference
79 * detected by this class should halt further comparison or not
80 * @see ComparisonController#haltComparison(Difference)
81 */
82 public DifferenceEngine(ComparisonController controller) {
83 this(controller, null);
84 }
85
86 /**
87 * Simple constructor
88 * @param controller the instance used to determine whether a Difference
89 * detected by this class should halt further comparison or not
90 * @param matchTracker the instance that is notified on each
91 * successful match. May be null.
92 * @see ComparisonController#haltComparison(Difference)
93 * @see MatchTracker#matchFound(Difference)
94 */
95 public DifferenceEngine(ComparisonController controller,
96 MatchTracker matchTracker) {
97 this.controller = controller;
98 this.matchTracker = matchTracker;
99 this.controlTracker = new XpathNodeTracker();
100 this.testTracker = new XpathNodeTracker();
101 }
102
103 /**
104 * @param matchTracker the instance that is notified on each
105 * successful match. May be null.
106 */
107 public void setMatchTracker(MatchTracker matchTracker) {
108 this.matchTracker = matchTracker;
109 }
110
111 /**
112 * Entry point for Node comparison testing.
113 * @param control Control XML to compare
114 * @param test Test XML to compare
115 * @param listener Notified of any {@link Difference differences} detected
116 * during node comparison testing
117 * @param elementQualifier Used to determine which elements qualify for
118 * comparison e.g. when a node has repeated child elements that may occur
119 * in any sequence and that sequence is not considered important.
120 */
121 public void compare(Node control, Node test, DifferenceListener listener,
122 ElementQualifier elementQualifier) {
123 controlTracker.reset();
124 testTracker.reset();
125 try {
126 compare(getNullOrNotNull(control), getNullOrNotNull(test),
127 control, test, listener, NODE_TYPE);
128 if (control!=null) {
129 compareNode(control, test, listener, elementQualifier);
130 }
131 } catch (DifferenceFoundException e) {
132 // thrown by the protected compare() method to terminate the
133 // comparison and unwind the call stack back to here
134 }
135 }
136
137 private String getNullOrNotNull(Node aNode) {
138 return aNode==null ? NULL_NODE : NOT_NULL_NODE;
139 }
140
141 /**
142 * First point of call: if nodes are comparable it compares node values then
143 * recurses to compare node children.
144 * @param control
145 * @param test
146 * @param listener
147 * @param elementQualifier
148 * @throws DifferenceFoundException
149 */
150 protected void compareNode(Node control, Node test,
151 DifferenceListener listener, ElementQualifier elementQualifier)
152 throws DifferenceFoundException {
153 boolean comparable = compareNodeBasics(control, test, listener);
154 boolean isDocumentNode = false;
155
156 if (comparable) {
157 switch (control.getNodeType()) {
158 case Node.ELEMENT_NODE:
159 compareElement((Element)control, (Element)test, listener);
160 break;
161 case Node.CDATA_SECTION_NODE:
162 case Node.TEXT_NODE:
163 compareText((CharacterData) control,
164 (CharacterData) test, listener);
165 break;
166 case Node.COMMENT_NODE:
167 compareComment((Comment)control, (Comment)test, listener);
168 break;
169 case Node.DOCUMENT_TYPE_NODE:
170 compareDocumentType((DocumentType)control,
171 (DocumentType)test, listener);
172 break;
173 case Node.PROCESSING_INSTRUCTION_NODE:
174 compareProcessingInstruction((ProcessingInstruction)control,
175 (ProcessingInstruction)test, listener);
176 break;
177 case Node.DOCUMENT_NODE:
178 isDocumentNode = true;
179 compareDocument((Document)control, (Document) test,
180 listener, elementQualifier);
181 break;
182 default:
183 listener.skippedComparison(control, test);
184 }
185 }
186
187 compareHasChildNodes(control, test, listener);
188 if (isDocumentNode) {
189 Element controlElement = ((Document)control).getDocumentElement();
190 Element testElement = ((Document)test).getDocumentElement();
191 if (controlElement!=null && testElement!=null) {
192 compareNode(controlElement, testElement, listener, elementQualifier);
193 }
194 } else {
195 controlTracker.indent();
196 testTracker.indent();
197 compareNodeChildren(control, test, listener, elementQualifier);
198 controlTracker.outdent();
199 testTracker.outdent();
200 }
201 }
202
203 /**
204 * Compare two Documents for doctype and then element differences
205 * @param control
206 * @param test
207 * @param listener
208 * @param elementQualifier
209 * @throws DifferenceFoundException
210 */
211 protected void compareDocument(Document control, Document test,
212 DifferenceListener listener, ElementQualifier elementQualifier)
213 throws DifferenceFoundException {
214 DocumentType controlDoctype = control.getDoctype();
215 DocumentType testDoctype = test.getDoctype();
216 compare(getNullOrNotNull(controlDoctype),
217 getNullOrNotNull(testDoctype),
218 controlDoctype, testDoctype, listener,
219 HAS_DOCTYPE_DECLARATION);
220 if (controlDoctype!=null && testDoctype!=null) {
221 compareNode(controlDoctype, testDoctype, listener, elementQualifier);
222 }
223 }
224
225 /**
226 * Compares node type and node namespace characteristics: basically
227 * determines if nodes are comparable further
228 * @param control
229 * @param test
230 * @param listener
231 * @return true if the nodes are comparable further, false otherwise
232 * @throws DifferenceFoundException
233 */
234 protected boolean compareNodeBasics(Node control, Node test,
235 DifferenceListener listener) throws DifferenceFoundException {
236 controlTracker.visited(control);
237 testTracker.visited(test);
238
239 Short controlType = new Short(control.getNodeType());
240 Short testType = new Short(test.getNodeType());
241
242 boolean textAndCDATA = comparingTextAndCDATA(control.getNodeType(),
243 test.getNodeType());
244 if (!textAndCDATA) {
245 compare(controlType, testType, control, test, listener,
246 NODE_TYPE);
247 }
248 compare(control.getNamespaceURI(), test.getNamespaceURI(),
249 control, test, listener, NAMESPACE_URI);
250 compare(control.getPrefix(), test.getPrefix(),
251 control, test, listener, NAMESPACE_PREFIX);
252
253 return textAndCDATA || controlType.equals(testType);
254 }
255
256 private boolean comparingTextAndCDATA(short controlType, short testType) {
257 return XMLUnit.getIgnoreDiffBetweenTextAndCDATA() &&
258 (controlType == Node.TEXT_NODE
259 && testType == Node.CDATA_SECTION_NODE
260 ||
261 testType == Node.TEXT_NODE
262 && controlType == Node.CDATA_SECTION_NODE);
263 }
264
265 /**
266 * Compare the number of children, and if the same, compare the actual
267 * children via their NodeLists.
268 * @param control
269 * @param test
270 * @param listener
271 * @throws DifferenceFoundException
272 */
273 protected void compareHasChildNodes(Node control, Node test,
274 DifferenceListener listener) throws DifferenceFoundException {
275 Boolean controlHasChildren = hasChildNodes(control);
276 Boolean testHasChildren = hasChildNodes(test);
277 compare(controlHasChildren, testHasChildren, control, test,
278 listener, HAS_CHILD_NODES);
279 }
280
281 /**
282 * Tests whether a Node has children, taking ignoreComments
283 * setting into account.
284 */
285 private Boolean hasChildNodes(Node n) {
286 boolean flag = n.hasChildNodes();
287 if (flag && XMLUnit.getIgnoreComments()) {
288 List nl = nodeList2List(n.getChildNodes());
289 flag = !nl.isEmpty();
290 }
291 return flag ? Boolean.TRUE : Boolean.FALSE;
292 }
293
294 /**
295 * Returns the NodeList's Nodes as List, taking ignoreComments
296 * into account.
297 */
298 static List nodeList2List(NodeList nl) {
299 int len = nl.getLength();
300 ArrayList l = new ArrayList(len);
301 for (int i = 0; i < len; i++) {
302 Node n = nl.item(i);
303 if (!XMLUnit.getIgnoreComments() || !(n instanceof Comment)) {
304 l.add(n);
305 }
306 }
307 return l;
308 }
309
310 /**
311 * Compare the number of children, and if the same, compare the actual
312 * children via their NodeLists.
313 * @param control
314 * @param test
315 * @param listener
316 * @param elementQualifier
317 * @throws DifferenceFoundException
318 */
319 protected void compareNodeChildren(Node control, Node test,
320 DifferenceListener listener, ElementQualifier elementQualifier)
321 throws DifferenceFoundException {
322
323 List controlChildren = nodeList2List(control.getChildNodes());
324 List testChildren = nodeList2List(test.getChildNodes());
325
326 Integer controlLength = new Integer(controlChildren.size());
327 Integer testLength = new Integer(testChildren.size());
328 compare(controlLength, testLength, control, test, listener,
329 CHILD_NODELIST_LENGTH);
330
331 if (control.hasChildNodes() || test.hasChildNodes()) {
332 if (!control.hasChildNodes()) {
333 for (Iterator iter = testChildren.iterator(); iter.hasNext();) {
334 missingNode(null, (Node) iter.next(), listener);
335 }
336 } else if (!test.hasChildNodes()) {
337 for (Iterator iter = controlChildren.iterator(); iter.hasNext();) {
338 missingNode((Node) iter.next(), null, listener);
339 }
340 } else {
341 compareNodeList(controlChildren, testChildren,
342 controlLength.intValue(), listener, elementQualifier);
343 }
344 }
345 }
346
347 /**
348 * Compare the contents of two node list one by one, assuming that order
349 * of children is NOT important: matching begins at same position in test
350 * list as control list.
351 * @param control
352 * @param test
353 * @param numNodes convenience parameter because the calling method should
354 * know the value already
355 * @param listener
356 * @param elementQualifier used to determine which of the child elements in
357 * the test NodeList should be compared to the current child element in the
358 * control NodeList.
359 * @throws DifferenceFoundException
360 * @deprecated Use the version with List arguments instead
361 */
362 protected void compareNodeList(final NodeList control, final NodeList test,
363 final int numNodes,
364 final DifferenceListener listener,
365 final ElementQualifier elementQualifier)
366 throws DifferenceFoundException {
367 compareNodeList(nodeList2List(control), nodeList2List(test),
368 numNodes, listener, elementQualifier);
369 }
370
371 /**
372 * Compare the contents of two node list one by one, assuming that order
373 * of children is NOT important: matching begins at same position in test
374 * list as control list.
375 * @param control
376 * @param test
377 * @param numNodes convenience parameter because the calling method should
378 * know the value already
379 * @param listener
380 * @param elementQualifier used to determine which of the child elements in
381 * the test NodeList should be compared to the current child element in the
382 * control NodeList.
383 * @throws DifferenceFoundException
384 */
385 protected void compareNodeList(final List controlChildren,
386 final List testChildren,
387 final int numNodes,
388 final DifferenceListener listener,
389 final ElementQualifier elementQualifier)
390 throws DifferenceFoundException {
391
392 int j = 0;
393 final int lastTestNode = testChildren.size() - 1;
394 testTracker.preloadChildList(testChildren);
395
396 HashMap/*<Node, Node>*/ matchingNodes = new HashMap();
397 HashMap/*<Node, Integer>*/ matchingNodeIndexes = new HashMap();
398
399 List/*<Node>*/ unmatchedTestNodes = new ArrayList(testChildren);
400
401 // first pass to find the matching nodes in control and test docs
402 for (int i=0; i < numNodes; ++i) {
403 Node nextControl = (Node) controlChildren.get(i);
404 boolean matchOnElement = nextControl instanceof Element;
405 short findNodeType = nextControl.getNodeType();
406 int startAt = ( i > lastTestNode ? lastTestNode : i);
407 j = startAt;
408
409 boolean matchFound = false;
410
411 /*
412 * XMLUnit 1.2 and earlier don't check whether the
413 * "matched" test node has already been matched to a
414 * different control node and will happily match the same
415 * test node to each and every control node, if necessary.
416 *
417 * I (Stefan) feel this is wrong but can't change it
418 * without breaking backwards compatibility
419 * (testXpathLocation12 in test_DifferenceEngine which
420 * predates XMLUnit 1.0 fails, so at one point it has been
421 * the expected and intended behaviour).
422 *
423 * As a side effect it may leave test nodes inside the
424 * unmatched list, see
425 * https://sourceforge.net/tracker/?func=detail&aid=2807167&group_id=23187&atid=377768
426 *
427 * To overcome the later problem the code will now prefer
428 * test nodes that haven't already been matched to any
429 * other node and falls back to the first
430 * (multiply-)matched node if none could be found. Yes,
431 * this is strange.
432 */
433 int fallbackMatch = -1;
434
435 while (!matchFound) {
436 Node t = (Node) testChildren.get(j);
437 if (findNodeType == t.getNodeType()
438 || comparingTextAndCDATA(findNodeType, t.getNodeType())) {
439 matchFound = !matchOnElement
440 || elementQualifier == null
441 || elementQualifier
442 .qualifyForComparison((Element) nextControl,
443 (Element) t);
444 }
445 if (matchFound && !unmatchedTestNodes.contains(t)) {
446 /*
447 * test node already matched to a different
448 * control node, try the other test nodes first
449 * but keep this as "fallback" (unless there
450 * already is a fallback)
451 */
452 if (fallbackMatch < 0) {
453 fallbackMatch = j;
454 }
455 matchFound = false;
456 }
457 if (!matchFound) {
458 ++j;
459 if (j > lastTestNode) {
460 j = 0;
461 }
462 if (j == startAt) {
463 // been through all children
464 break;
465 }
466 }
467 }
468 if (!matchFound && XMLUnit.getCompareUnmatched()
469 && fallbackMatch >= 0) {
470 matchFound = true;
471 j = fallbackMatch;
472 }
473 if (matchFound) {
474 matchingNodes.put(nextControl, testChildren.get(j));
475 matchingNodeIndexes.put(nextControl, new Integer(j));
476 unmatchedTestNodes.remove(testChildren.get(j));
477 }
478 }
479
480 // next, do the actual comparision on those that matched - or
481 // match them against the first test nodes that didn't match
482 // any other control nodes
483 for (int i=0; i < numNodes; ++i) {
484 Node nextControl = (Node) controlChildren.get(i);
485 Node nextTest = (Node) matchingNodes.get(nextControl);
486 Integer testIndex = (Integer) matchingNodeIndexes.get(nextControl);
487 if (nextTest == null && XMLUnit.getCompareUnmatched()
488 && !unmatchedTestNodes.isEmpty()) {
489 nextTest = (Node) unmatchedTestNodes.get(0);
490 testIndex = new Integer(testChildren.indexOf(nextTest));
491 unmatchedTestNodes.remove(0);
492 }
493 if (nextTest != null) {
494 compareNode(nextControl, nextTest, listener, elementQualifier);
495 compare(new Integer(i), testIndex,
496 nextControl, nextTest, listener,
497 CHILD_NODELIST_SEQUENCE);
498 } else {
499 missingNode(nextControl, null, listener);
500 }
501 }
502
503 // now handle remaining unmatched test nodes
504 for (Iterator iter = unmatchedTestNodes.iterator(); iter.hasNext();) {
505 missingNode(null, (Node) iter.next(), listener);
506 }
507 }
508
509 private void missingNode(Node control, Node test,
510 DifferenceListener listener)
511 throws DifferenceFoundException {
512 if (control != null) {
513 controlTracker.visited(control);
514 compare(getQName(control), null, control, null,
515 listener, CHILD_NODE_NOT_FOUND, controlTracker, null);
516 } else {
517 testTracker.visited(test);
518 compare(null, getQName(test), null, test, listener,
519 CHILD_NODE_NOT_FOUND, null, testTracker);
520 }
521 }
522
523 /**
524 * @param aNode
525 * @return true if the node has a namespace
526 */
527 private boolean isNamespaced(Node aNode) {
528 String namespace = aNode.getNamespaceURI();
529 return namespace != null && namespace.length() > 0;
530 }
531
532 /**
533 * Compare 2 elements and their attributes
534 * @param control
535 * @param test
536 * @param listener
537 * @throws DifferenceFoundException
538 */
539 protected void compareElement(Element control, Element test,
540 DifferenceListener listener) throws DifferenceFoundException {
541 compare(getUnNamespacedNodeName(control), getUnNamespacedNodeName(test),
542 control, test, listener, ELEMENT_TAG_NAME);
543
544 NamedNodeMap controlAttr = control.getAttributes();
545 Integer controlNonXmlnsAttrLength =
546 getNonSpecialAttrLength(controlAttr);
547 NamedNodeMap testAttr = test.getAttributes();
548 Integer testNonXmlnsAttrLength = getNonSpecialAttrLength(testAttr);
549 compare(controlNonXmlnsAttrLength, testNonXmlnsAttrLength,
550 control, test, listener, ELEMENT_NUM_ATTRIBUTES);
551
552 compareElementAttributes(control, test, controlAttr, testAttr,
553 listener);
554 }
555
556 /**
557 * The number of attributes not related to namespace declarations
558 * and/or Schema location.
559 */
560 private Integer getNonSpecialAttrLength(NamedNodeMap attributes) {
561 int length = 0, maxLength = attributes.getLength();
562 for (int i = 0; i < maxLength; ++i) {
563 Attr a = (Attr) attributes.item(i);
564 if (!isXMLNSAttribute(a)
565 && !isRecognizedXMLSchemaInstanceAttribute(a)) {
566 ++length;
567 }
568 }
569 return new Integer(length);
570 }
571
572 void compareElementAttributes(Element control, Element test,
573 NamedNodeMap controlAttr,
574 NamedNodeMap testAttr,
575 DifferenceListener listener)
576 throws DifferenceFoundException {
577 ArrayList unmatchedTestAttrs = new ArrayList();
578 for (int i=0; i < testAttr.getLength(); ++i) {
579 Attr nextAttr = (Attr) testAttr.item(i);
580 if (!isXMLNSAttribute(nextAttr)) {
581 unmatchedTestAttrs.add(nextAttr);
582 }
583 }
584
585 for (int i=0; i < controlAttr.getLength(); ++i) {
586 Attr nextAttr = (Attr) controlAttr.item(i);
587 if (isXMLNSAttribute(nextAttr)) {
588 // xml namespacing is handled in compareNodeBasics
589 } else {
590 boolean isNamespacedAttr = isNamespaced(nextAttr);
591 String attrName = getUnNamespacedNodeName(nextAttr, isNamespacedAttr);
592 Attr compareTo = null;
593
594 if (isNamespacedAttr) {
595 compareTo = (Attr) testAttr.getNamedItemNS(
596 nextAttr.getNamespaceURI(), attrName);
597 } else {
598 compareTo = (Attr) testAttr.getNamedItem(attrName);
599 }
600
601 if (compareTo != null) {
602 unmatchedTestAttrs.remove(compareTo);
603 }
604
605 if (isRecognizedXMLSchemaInstanceAttribute(nextAttr)) {
606 compareRecognizedXMLSchemaInstanceAttribute(nextAttr,
607 compareTo,
608 listener);
609
610 } else if (compareTo != null) {
611 compareAttribute(nextAttr, compareTo, listener);
612
613 if (!XMLUnit.getIgnoreAttributeOrder()) {
614 Attr attributeItem = (Attr) testAttr.item(i);
615 String testAttrName = ATTRIBUTE_ABSENT;
616 if (attributeItem != null) {
617 testAttrName =
618 getUnNamespacedNodeName(attributeItem);
619 }
620 compare(attrName, testAttrName,
621 nextAttr, compareTo, listener, ATTR_SEQUENCE);
622 }
623 } else {
624 controlTracker.clearTrackedAttribute();
625 controlTracker.visited(nextAttr);
626 testTracker.clearTrackedAttribute();
627 compare(getQName(nextAttr, isNamespacedAttr), null,
628 control, test, listener,
629 ATTR_NAME_NOT_FOUND);
630 }
631 }
632 }
633
634 for (Iterator iter = unmatchedTestAttrs.iterator(); iter.hasNext(); ) {
635 Attr nextAttr = (Attr) iter.next();
636 if (isRecognizedXMLSchemaInstanceAttribute(nextAttr)) {
637 compareRecognizedXMLSchemaInstanceAttribute(null, nextAttr,
638 listener);
639 } else {
640 controlTracker.clearTrackedAttribute();
641 testTracker.clearTrackedAttribute();
642 testTracker.visited(nextAttr);
643 compare(null,
644 getQName(nextAttr),
645 control, test, listener, ATTR_NAME_NOT_FOUND);
646 }
647 }
648
649 controlTracker.clearTrackedAttribute();
650 testTracker.clearTrackedAttribute();
651 }
652
653 private String getUnNamespacedNodeName(Node aNode) {
654 return getUnNamespacedNodeName(aNode, isNamespaced(aNode));
655 }
656
657 private String getUnNamespacedNodeName(Node aNode, boolean isNamespacedNode) {
658 if (isNamespacedNode) {
659 return aNode.getLocalName();
660 }
661 return aNode.getNodeName();
662 }
663
664 private String getQName(Node aNode) {
665 return getQName(aNode, isNamespaced(aNode));
666 }
667
668 private String getQName(Node aNode, boolean isNamespacedNode) {
669 if (isNamespacedNode) {
670 return "{" + aNode.getNamespaceURI() + "}" + aNode.getLocalName();
671 }
672 return aNode.getNodeName();
673 }
674
675 /**
676 * @param attribute
677 * @return true if the attribute represents a namespace declaration
678 */
679 private boolean isXMLNSAttribute(Attr attribute) {
680 return XMLConstants.XMLNS_PREFIX.equals(attribute.getPrefix()) ||
681 XMLConstants.XMLNS_PREFIX.equals(attribute.getName());
682 }
683
684 /**
685 * @param attr
686 * @return true if the attribute is an XML Schema Instance
687 * namespace attribute XMLUnit treats in a special way.
688 */
689 private boolean isRecognizedXMLSchemaInstanceAttribute(Attr attr) {
690 return XMLConstants
691 .W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(attr.getNamespaceURI())
692 && (XMLConstants
693 .W3C_XML_SCHEMA_INSTANCE_SCHEMA_LOCATION_ATTR
694 .equals(attr.getLocalName())
695 || XMLConstants
696 .W3C_XML_SCHEMA_INSTANCE_NO_NAMESPACE_SCHEMA_LOCATION_ATTR
697 .equals(attr.getLocalName()));
698 }
699
700 /**
701 * Compare two attributes
702 * @param control
703 * @param test
704 * @param listener
705 * @throws DifferenceFoundException
706 */
707 protected void compareRecognizedXMLSchemaInstanceAttribute(Attr control,
708 Attr test,
709 DifferenceListener listener)
710 throws DifferenceFoundException {
711 Attr nonNullNode = control != null ? control : test;
712 Difference d =
713 XMLConstants.W3C_XML_SCHEMA_INSTANCE_SCHEMA_LOCATION_ATTR
714 .equals(nonNullNode.getLocalName())
715 ? SCHEMA_LOCATION : NO_NAMESPACE_SCHEMA_LOCATION;
716
717 if (control != null) {
718 controlTracker.visited(control);
719 }
720 if (test != null) {
721 testTracker.visited(test);
722 }
723
724 compare(control != null ? control.getValue() : ATTRIBUTE_ABSENT,
725 test != null ? test.getValue() : ATTRIBUTE_ABSENT,
726 control, test, listener, d);
727 }
728
729 /**
730 * @param attr
731 * @return true if the attribute is an XML Schema Instance
732 * namespace attribute XMLUnit treats in a special way.
733 */
734 private boolean isXMLSchemaTypeAttribute(Attr attr) {
735 return XMLConstants
736 .W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(attr.getNamespaceURI())
737 && XMLConstants.W3C_XML_SCHEMA_INSTANCE_TYPE_ATTR
738 .equals(attr.getLocalName());
739 }
740
741 /**
742 * Compare two attributes
743 * @param control
744 * @param test
745 * @param listener
746 * @throws DifferenceFoundException
747 */
748 protected void compareAttribute(Attr control, Attr test,
749 DifferenceListener listener) throws DifferenceFoundException {
750 controlTracker.visited(control);
751 testTracker.visited(test);
752
753 compare(control.getPrefix(), test.getPrefix(), control, test,
754 listener, NAMESPACE_PREFIX);
755 if (isXMLSchemaTypeAttribute(control)
756 && isXMLSchemaTypeAttribute(test)) {
757 compareXMLSchemaTypeAttributeValues(control, test, listener);
758 } else {
759 compare(control.getValue(), test.getValue(), control, test,
760 listener, ATTR_VALUE);
761 }
762 compare(control.getSpecified() ? Boolean.TRUE : Boolean.FALSE,
763 test.getSpecified() ? Boolean.TRUE : Boolean.FALSE,
764 control, test, listener, ATTR_VALUE_EXPLICITLY_SPECIFIED);
765 }
766
767 private void compareXMLSchemaTypeAttributeValues(Attr control, Attr test,
768 DifferenceListener listener)
769 throws DifferenceFoundException {
770 String controlValue = control.getValue();
771 String testValue = test.getValue();
772
773 String controlLocal = controlValue;
774 String controlPrefix = "";
775 String testLocal = testValue;
776 String testPrefix = "";
777 int controlColon = controlValue.indexOf(":");
778 if (controlColon >= 0 && controlColon < controlValue.length() - 1) {
779 controlLocal = controlValue.substring(controlColon + 1);
780 controlPrefix = controlValue.substring(0, controlColon);
781 }
782 int testColon = testValue.indexOf(":");
783 if (testColon >= 0 && testColon < testValue.length() - 1) {
784 testLocal = testValue.substring(testColon + 1);
785 testPrefix = testValue.substring(0, testColon);
786 }
787 compare("{" + findNamespaceURIForPrefix(control, controlPrefix) + "}"
788 + controlLocal,
789 "{" + findNamespaceURIForPrefix(test, testPrefix) + "}"
790 + testLocal, control, test, listener, ATTR_VALUE);
791 }
792
793 /**
794 * Compare two CDATA sections - unused, kept for backwards compatibility
795 * @param control
796 * @param test
797 * @param listener
798 * @throws DifferenceFoundException
799 */
800 protected void compareCDataSection(CDATASection control, CDATASection test,
801 DifferenceListener listener) throws DifferenceFoundException {
802 compareText(control, test, listener);
803 }
804
805 /**
806 * Compare two comments
807 * @param control
808 * @param test
809 * @param listener
810 * @throws DifferenceFoundException
811 */
812 protected void compareComment(Comment control, Comment test,
813 DifferenceListener listener) throws DifferenceFoundException {
814 if (!XMLUnit.getIgnoreComments()) {
815 compareCharacterData(control, test, listener, COMMENT_VALUE);
816 }
817 }
818
819 /**
820 * Compare two DocumentType nodes
821 * @param control
822 * @param test
823 * @param listener
824 * @throws DifferenceFoundException
825 */
826 protected void compareDocumentType(DocumentType control, DocumentType test,
827 DifferenceListener listener) throws DifferenceFoundException {
828 compare(control.getName(), test.getName(), control, test, listener,
829 DOCTYPE_NAME);
830 compare(control.getPublicId(), test.getPublicId(), control, test, listener,
831 DOCTYPE_PUBLIC_ID);
832
833 compare(control.getSystemId(), test.getSystemId(),
834 control, test, listener, DOCTYPE_SYSTEM_ID);
835 }
836
837 /**
838 * Compare two processing instructions
839 * @param control
840 * @param test
841 * @param listener
842 * @throws DifferenceFoundException
843 */
844 protected void compareProcessingInstruction(ProcessingInstruction control,
845 ProcessingInstruction test, DifferenceListener listener)
846 throws DifferenceFoundException {
847 compare(control.getTarget(), test.getTarget(), control, test, listener,
848 PROCESSING_INSTRUCTION_TARGET);
849 compare(control.getData(), test.getData(), control, test, listener,
850 PROCESSING_INSTRUCTION_DATA);
851 }
852
853 /**
854 * Compare text - unused, kept for backwards compatibility
855 * @param control
856 * @param test
857 * @param listener
858 * @throws DifferenceFoundException
859 */
860 protected void compareText(Text control, Text test,
861 DifferenceListener listener)
862 throws DifferenceFoundException {
863 compareText((CharacterData) control, (CharacterData) test, listener);
864 }
865
866 /**
867 * Compare text
868 * @param control
869 * @param test
870 * @param listener
871 * @throws DifferenceFoundException
872 */
873 protected void compareText(CharacterData control, CharacterData test,
874 DifferenceListener listener)
875 throws DifferenceFoundException {
876 compareCharacterData(control, test, listener,
877 control instanceof CDATASection ? CDATA_VALUE : TEXT_VALUE);
878 }
879
880 /**
881 * Character comparison method used by comments, text and CDATA sections
882 * @param control
883 * @param test
884 * @param listener
885 * @param differenceType
886 * @throws DifferenceFoundException
887 */
888 private void compareCharacterData(CharacterData control, CharacterData test,
889 DifferenceListener listener, Difference difference)
890 throws DifferenceFoundException {
891 compare(control.getData(), test.getData(), control, test, listener,
892 difference);
893 }
894
895 /**
896 * If the expected and actual values are unequal then inform the listener of
897 * a difference and throw a DifferenceFoundException.
898 * @param expected
899 * @param actual
900 * @param control
901 * @param test
902 * @param listener
903 * @param differenceType
904 * @throws DifferenceFoundException
905 */
906 protected void compare(Object expected, Object actual,
907 Node control, Node test, DifferenceListener listener, Difference difference)
908 throws DifferenceFoundException {
909 compare(expected, actual, control, test, listener, difference,
910 controlTracker, testTracker);
911 }
912
913 /**
914 * If the expected and actual values are unequal then inform the listener of
915 * a difference and throw a DifferenceFoundException.
916 * @param expected
917 * @param actual
918 * @param control
919 * @param test
920 * @param listener
921 * @param differenceType
922 * @throws DifferenceFoundException
923 */
924 protected void compare(Object expected, Object actual,
925 Node control, Node test, DifferenceListener listener,
926 Difference difference, XpathNodeTracker controlLoc,
927 XpathNodeTracker testLoc)
928 throws DifferenceFoundException {
929 NodeDetail controlDetail = new NodeDetail(String.valueOf(expected),
930 control,
931 controlLoc == null ? null
932 : controlLoc.toXpathString());
933 NodeDetail testDetail = new NodeDetail(String.valueOf(actual),
934 test,
935 testLoc == null ? null
936 : testLoc.toXpathString());
937 Difference differenceInstance = new Difference(difference,
938 controlDetail, testDetail);
939 if (unequal(expected, actual)) {
940 listener.differenceFound(differenceInstance);
941 if (controller.haltComparison(differenceInstance)) {
942 throw flowControlException;
943 }
944 } else if (matchTracker != null) {
945 matchTracker.matchFound(differenceInstance);
946 }
947 }
948
949 /**
950 * Test two possibly null values for inequality
951 * @param expected
952 * @param actual
953 * @return TRUE if the values are neither both null, nor equals() equal
954 */
955 private boolean unequal(Object expected, Object actual) {
956 return (expected==null ? actual!=null : unequalNotNull(expected, actual));
957 }
958
959 /**
960 * Test two non-null values for inequality
961 * @param expected
962 * @param actual
963 * @return TRUE if the values are not equals() equal (taking whitespace
964 * into account if necessary)
965 */
966 private boolean unequalNotNull(Object expected, Object actual) {
967 if ((XMLUnit.getIgnoreWhitespace() || XMLUnit.getNormalizeWhitespace())
968 && expected instanceof String && actual instanceof String) {
969 String expectedString = ((String) expected).trim();
970 String actualString = ((String) actual).trim();
971 if (XMLUnit.getNormalizeWhitespace()) {
972 expectedString = normalizeWhitespace(expectedString);
973 actualString = normalizeWhitespace(actualString);
974 }
975 return !expectedString.equals(actualString);
976 }
977 return !(expected.equals(actual));
978 }
979
980 /**
981 * Replace all whitespace characters with SPACE and collapse
982 * consecutive whitespace chars to a single SPACE.
983 */
984 final static String normalizeWhitespace(String orig) {
985 StringBuffer sb = new StringBuffer();
986 boolean lastCharWasWhitespace = false;
987 boolean changed = false;
988 char[] characters = orig.toCharArray();
989 for (int i = 0; i < characters.length; i++) {
990 if (Character.isWhitespace(characters[i])) {
991 if (lastCharWasWhitespace) {
992 // suppress character
993 changed = true;
994 } else {
995 sb.append(' ');
996 changed |= characters[i] != ' ';
997 lastCharWasWhitespace = true;
998 }
999 } else {
1000 sb.append(characters[i]);
1001 lastCharWasWhitespace = false;
1002 }
1003 }
1004 return changed ? sb.toString() : orig;
1005 }
1006
1007 /**
1008 * Try to find the namespace URI that is mapped to the given
1009 * prefix at the given node.
1010 */
1011 private String findNamespaceURIForPrefix(Node onNode, String prefix) {
1012 if (onNode != null && onNode instanceof Attr) {
1013 onNode = ((Attr) onNode).getOwnerElement();
1014 }
1015 while (onNode != null && onNode.getNodeType() != Node.ELEMENT_NODE) {
1016 onNode = onNode.getParentNode();
1017 }
1018 if (onNode == null) {
1019 return null;
1020 }
1021
1022 NamedNodeMap attrs = onNode.getAttributes();
1023 Attr attr = null;
1024 if (prefix == null || "".equals(prefix)) {
1025 attr = (Attr) attrs.getNamedItem(XMLConstants.XMLNS_PREFIX);
1026 } else {
1027 attr = (Attr) attrs.getNamedItemNS(XMLConstants.XMLNS_ATTRIBUTE_URI, prefix);
1028 }
1029 if (attr != null) {
1030 return attr.getValue();
1031 }
1032 return findNamespaceURIForPrefix(onNode.getParentNode(), prefix);
1033 }
1034
1035 /**
1036 * Marker exception thrown by the protected compare() method and passed
1037 * upwards through the call stack to the public compare() method.
1038 */
1039 protected static final class DifferenceFoundException extends Exception {
1040 private DifferenceFoundException() {
1041 super("This exception is used to control flow");
1042 }
1043 }
1044
1045 /**
1046 * Exception instance used internally to control flow
1047 * when a difference is found
1048 */
1049 private static final DifferenceFoundException flowControlException =
1050 new DifferenceFoundException();
1051 }
0 --- src/java/org/custommonkey/xmlunit/DifferenceEngine.java (revision 578)
1 +++ src/java/org/custommonkey/xmlunit/DifferenceEngine.java (working copy)
2 @@ -660,7 +662,17 @@
3 return aNode.getNodeName();
4 }
5
6 + private String getQName(Node aNode) {
7 + return getQName(aNode, isNamespaced(aNode));
8 + }
9
10 + private String getQName(Node aNode, boolean isNamespacedNode) {
11 + if (isNamespacedNode) {
12 + return "{" + aNode.getNamespaceURI() + "}" + aNode.getLocalName();
13 + }
14 + return aNode.getNodeName();
15 + }
16 +
17 /**
18 * @param attribute
19 * @return true if the attribute represents a namespace declaration
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Node;
39
40 /**
41 * Listener for callbacks from a
42 * {@link DifferenceEngine#compare DifferenceEngine comparison}.
43 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
44 */
45 public interface DifferenceListener {
46 /**
47 * Standard return value for the <code>differenceFound</code> method.
48 * Indicates that the <code>Difference</code> is interpreted as defined
49 * in {@link DifferenceConstants DifferenceConstants}.
50 */
51 int RETURN_ACCEPT_DIFFERENCE = 0;
52 /**
53 * Override return value for the <code>differenceFound</code> method.
54 * Indicates that the nodes identified as being different should be
55 * interpreted as being identical.
56 */
57 int RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL = 1;
58 /**
59 * Override return value for the <code>differenceFound</code> method.
60 * Indicates that the nodes identified as being different should be
61 * interpreted as being similar.
62 */
63 int RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR = 2;
64 /**
65 * Override return value for the <code>differenceFound</code> method.
66 * Indicates that the nodes identified as being similar should be
67 * interpreted as being different.
68 */
69 int RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT = 3;
70 /**
71 * Receive notification that 2 nodes are different.
72 * @param difference a Difference instance as defined in {@link
73 * DifferenceConstants DifferenceConstants} describing the cause
74 * of the difference and containing the detail of the nodes that
75 * differ
76 * @return int one of the RETURN_... constants describing how this
77 * difference was interpreted
78 */
79 int differenceFound(Difference difference);
80
81 /**
82 * Receive notification that a comparison between 2 nodes has been skipped
83 * because the node types are not comparable by the DifferenceEngine
84 * @param control the control node being compared
85 * @param test the test node being compared
86 * @see DifferenceEngine
87 */
88 void skippedComparison(Node control, Node test);
89
90 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.BufferedInputStream;
39 import java.io.ByteArrayOutputStream;
40 import java.io.InputStream;
41 import java.io.IOException;
42
43 /**
44 * Adapts the marked-up content in a source InputStream to specify that it
45 * conforms to a different DTD.
46 * Combines InputStream semantics with the ability to specify a target doctype
47 * for a byte stream containing XML markup.
48 * Used by Validator class to wrap an InputStrea, when performing validation of a
49 * document against a DTD.
50 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
51 */
52 public class DoctypeInputStream extends InputStream {
53
54 private final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
55 private final InputStream wrappedStream;
56 private final DoctypeSupport support;
57
58 /**
59 * Create an InputStream whose XML content is provided by the
60 * originalSource with the exception of the DOCTYPE which is
61 * provided by the doctypeName and systemID.
62 * @param originalSource
63 * @param doctypeName
64 * @param systemID
65 */
66 public DoctypeInputStream(InputStream originalSource, String encoding,
67 String doctypeName, String systemID) {
68 wrappedStream = originalSource instanceof BufferedInputStream
69 ? originalSource : new BufferedInputStream(originalSource);
70 support =
71 new DoctypeSupport(doctypeName, systemID,
72 new DoctypeSupport.Readable() {
73 public int read() throws IOException {
74 return wrappedStream.read();
75 }
76 },
77 false, encoding);
78 }
79
80 /**
81 * @return the content of the original source, without amendments or
82 * substitutions. Safe to call multiple times.
83 * @throws IOException if thrown while reading from the original source
84 */
85 protected String getContent(String encoding) throws IOException {
86 if (baos.size() == 0) {
87 byte[] buffer = new byte[8192];
88 int bytesRead = -1;
89 while ((bytesRead = wrappedStream.read(buffer)) > -1) {
90 baos.write(buffer, 0, bytesRead);
91 }
92 }
93 return encoding == null ? baos.toString() : baos.toString(encoding);
94 }
95
96 /**
97 * Read DOCTYPE-replaced content from the wrapped InputStream
98 */
99 public int read() throws IOException {
100 return support.read();
101 }
102
103 public void close() throws IOException {
104 wrappedStream.close();
105 }
106 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.BufferedReader;
39 import java.io.IOException;
40 import java.io.Reader;
41
42 /**
43 * Adapts the marked-up content in a source Reader to specify that it
44 * conforms to a different DTD.
45 * Combines Reader semantics with the ability to specify a target doctype
46 * for a character stream containing XML markup.
47 * Used by Validator class to wrap a Reader when performing validation of a
48 * document against a DTD.
49 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
50 */
51 public class DoctypeReader extends Reader {
52
53 private final Reader originalReader;
54 private final StringBuffer sourceBuffer = new StringBuffer(1024);
55
56 private final DoctypeSupport support;
57
58 /**
59 * Create a Reader whose XML content is provided by the originalSource with
60 * the exception of the DOCTYPE which is provided by the doctypeName
61 * and systemID.
62 * @param originalSource
63 * @param doctypeName
64 * @param systemID
65 */
66 public DoctypeReader(Reader originalSource, String doctypeName,
67 String systemID) {
68 originalReader = originalSource instanceof BufferedReader
69 ? originalSource : new BufferedReader(originalSource);
70 support =
71 new DoctypeSupport(doctypeName, systemID,
72 new DoctypeSupport.Readable() {
73 public int read() throws IOException {
74 return originalReader.read();
75 }
76 },
77 true, null);
78 }
79
80 /**
81 * @return the content of the original source, without amendments or
82 * substitutions. Safe to call multiple times.
83 * @throws IOException if thrown while reading from the original source
84 */
85 protected String getContent() throws IOException {
86 return getContent(originalReader).toString();
87 }
88
89 /**
90 * @param originalSource
91 * @return the contents of the originalSource within a StringBuffer
92 * @throws IOException if thrown while reading from the original source
93 */
94 private StringBuffer getContent(Reader originalSource)
95 throws IOException {
96 if (sourceBuffer.length() == 0) {
97 BufferedReader bufferedReader;
98 if (originalSource instanceof BufferedReader) {
99 bufferedReader = (BufferedReader) originalSource;
100 } else {
101 bufferedReader = new BufferedReader(originalSource);
102 }
103 String newline = System.getProperty("line.separator");
104 String source;
105 boolean atFirstLine = true;
106 while ((source = bufferedReader.readLine()) != null) {
107 if (atFirstLine) {
108 atFirstLine = false;
109 } else {
110 sourceBuffer.append(newline);
111 }
112 sourceBuffer.append(source);
113 }
114
115 bufferedReader.close();
116 }
117
118 return sourceBuffer;
119 }
120
121 /**
122 * Determine where to place the DOCTYPE declaration within some marked-up
123 * content
124 * @param withinContent
125 * @return
126 */
127 private int obsoleteFindStartDoctype(StringBuffer withinContent) {
128 int startAt = -1;
129 char curChar;
130 boolean canInsert = true;
131 for (int i = 0; startAt == -1; ++i) {
132 curChar = withinContent.charAt(i);
133 if (curChar == '<') {
134 switch (withinContent.charAt(i + 1)) {
135 case '?':
136 case '!':
137 case '-':
138 canInsert = false;
139 break;
140 default:
141 startAt = i;
142 }
143 } else if (curChar == '>') {
144 canInsert = true;
145 } else if (canInsert) {
146 startAt = i;
147 }
148 }
149 return startAt;
150 }
151
152 /**
153 * Perform DOCTYPE amendment / addition within some marked-up content
154 * @param withinContent
155 * @param doctypeName
156 * @param systemId
157 * @return the content, after DOCTYPE amendment / addition
158 * @deprecated this method is only here for BWC, it is no longer
159 * used by this class
160 */
161 public String replaceDoctype(StringBuffer withinContent,
162 String doctypeName, String systemId) {
163 String content = withinContent.toString();
164 int startDoctype = content.indexOf(DoctypeSupport.DOCTYPE);
165 boolean noCurrentDoctype = false;
166 if (startDoctype == -1) {
167 startDoctype = obsoleteFindStartDoctype(withinContent);
168 noCurrentDoctype = true;
169 }
170
171 int endDoctype = startDoctype + DoctypeSupport.DOCTYPE.length();
172
173 if (noCurrentDoctype) {
174 withinContent.insert(startDoctype,
175 DoctypeSupport.DOCTYPE_OPEN_DECL);
176 withinContent.insert(startDoctype
177 + DoctypeSupport.DOCTYPE_OPEN_DECL.length(),
178 DoctypeSupport.DOCTYPE);
179 endDoctype += DoctypeSupport.DOCTYPE_OPEN_DECL.length();
180 } else {
181 int startInternalDecl = content.indexOf('[', endDoctype);
182 if (startInternalDecl > 0) {
183 int endInternalDecl = content.indexOf(']', startInternalDecl);
184 withinContent.delete(endDoctype, endInternalDecl + 1);
185 } else {
186 int endDoctypeTag = content.indexOf('>', endDoctype);
187 withinContent.delete(endDoctype, endDoctypeTag);
188 }
189 }
190
191 int atPos = endDoctype;
192 withinContent.insert(atPos, doctypeName);
193 atPos += doctypeName.length();
194 withinContent.insert(atPos, DoctypeSupport.SYSTEM);
195 atPos += DoctypeSupport.SYSTEM.length();
196 withinContent.insert(atPos, systemId);
197 atPos += systemId.length();
198 withinContent.insert(atPos, '"');
199
200 if (noCurrentDoctype) {
201 withinContent.insert(++atPos, DoctypeSupport.DOCTYPE_CLOSE_DECL);
202 }
203 return withinContent.toString();
204 }
205
206 /**
207 * Read DOCTYPE-replaced content from the wrapped Reader
208 * @param cbuf
209 * @param off
210 * @param len
211 * @return The number of characters read, or -1 if the end of the
212 * stream has been reached
213 * @throws IOException
214 */
215 public int read(char cbuf[], int off, int len) throws IOException {
216 int startPos = off;
217 int currentlyRead;
218 while (off - startPos < len && (currentlyRead = read()) != -1) {
219 cbuf[off++] = (char) currentlyRead;
220 }
221 return off == startPos && len != 0 ? -1 : off - startPos;
222 }
223
224 /**
225 * Read DOCTYPE-replaced content from the wrapped Reader
226 */
227 public int read() throws IOException {
228 return support.read();
229 }
230
231 public void close() throws IOException {
232 originalReader.close();
233 }
234 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39
40 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
41 import org.custommonkey.xmlunit.util.IntegerBuffer;
42
43 /**
44 * Contains some common code for DoctypeReader and DoctypeInputStream.
45 *
46 * <p>When used with DoctypeInputStream it assumes that the whole
47 * DOCTYPE declaration consists of US-ASCII characters.</p>
48 */
49 final class DoctypeSupport {
50
51 static interface Readable {
52 int read() throws IOException;
53 }
54
55 final static String DOCTYPE_OPEN_DECL = "<!";
56 final static String DOCTYPE_CLOSE_DECL = ">";
57 final static String DOCTYPE = "DOCTYPE ";
58 final static String SYSTEM = " SYSTEM \"";
59 private final static int[] DOCTYPE_INTS = {
60 'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' '
61 };
62
63 private boolean hasSplit;
64 private final Readable original;
65 private Readable decl;
66 private Readable beforeDoctype;
67 private Readable afterDoctype;
68
69 /**
70 * Encapsulates a DOCTYPE declaration for the given name and system id.
71 */
72 DoctypeSupport(String name, String systemId, Readable original,
73 boolean characters, String encoding) {
74 this.original = original;
75
76 StringBuffer sb = new StringBuffer(DOCTYPE_OPEN_DECL);
77 sb.append(DOCTYPE).append(name).append(SYSTEM)
78 .append(systemId).append('\"').append(DOCTYPE_CLOSE_DECL);
79 String s = sb.toString();
80 IntegerBuffer buf =
81 new IntegerBuffer(s.length() * (characters ? 1 : 2));
82
83 if (characters) {
84 char[] c = s.toCharArray();
85 for (int i = 0; i < c.length; i++) {
86 buf.append(c[i]);
87 }
88 } else {
89 try {
90 byte[] b = encoding == null
91 ? s.getBytes() : s.getBytes(encoding);
92 for (int i = 0; i < b.length; i++) {
93 buf.append(b[i] & 0xFF);
94 }
95 } catch (java.io.UnsupportedEncodingException use) {
96 throw new XMLUnitRuntimeException("Unsupported encoding", use);
97 }
98 }
99
100 decl = new IntBufferReadable(buf);
101 }
102
103 /**
104 * Reads the next character from the declaration.
105 * @return -1 if the end of the declaration has been reached.
106 */
107 int read() throws IOException {
108 int nextInt = -1;
109 if (!hasSplit) {
110 split();
111 }
112 if (beforeDoctype != null) {
113 nextInt = beforeDoctype.read();
114 if (nextInt == -1) {
115 beforeDoctype = null;
116 }
117 }
118 if (nextInt == -1 && decl != null) {
119 nextInt = decl.read();
120 if (nextInt == -1) {
121 decl = null;
122 }
123 }
124 if (nextInt == -1 && afterDoctype != null) {
125 nextInt = afterDoctype.read();
126 if (nextInt == -1) {
127 afterDoctype = null;
128 }
129 }
130 if (nextInt == -1) {
131 nextInt = original.read();
132 }
133 return nextInt;
134 }
135
136 /**
137 * Reads enough of the original Readable to know where to place
138 * the declaration. Fills beforeDecl and afterDecl from the data
139 * read ahead. Swallows the original DOCTYPE if there is one.
140 */
141 private void split() throws IOException {
142 hasSplit = true;
143 IntegerBuffer before = new IntegerBuffer();
144 IntegerBuffer after = new IntegerBuffer();
145
146 int current;
147 boolean ready = false;
148 boolean stillNeedToSeeDoctype = true;
149 while (!ready && (current = original.read()) != -1) {
150 if (Character.isWhitespace((char) current)) {
151 before.append(current);
152 } else if (current == '<') {
153 // could be XML declaration, comment, PI, DOCTYPE
154 // or the first element
155 int[] elementOrDeclOr = readUntilCloseCharIsReached();
156 if (elementOrDeclOr.length > 0) {
157 if (elementOrDeclOr[0] == '?') {
158 // XML declaration or PI
159 before.append('<');
160 before.append(elementOrDeclOr);
161 } else if (elementOrDeclOr[0] != '!') {
162 // first element
163 after.append('<');
164 after.append(elementOrDeclOr);
165 stillNeedToSeeDoctype = false;
166 ready = true;
167 } else {
168 // comment or doctype
169 IntegerBuffer b =
170 new IntegerBuffer(elementOrDeclOr.length);
171 b.append(elementOrDeclOr);
172 if (b.indexOf(DOCTYPE_INTS) == -1) {
173 after.append('<');
174 after.append(elementOrDeclOr);
175 } else {
176 // swallow old declaration
177 stillNeedToSeeDoctype = false;
178 }
179 ready = true;
180 }
181 } else {
182 after.append('<');
183 stillNeedToSeeDoctype = false;
184 ready = true;
185 }
186 } else {
187 after.append(current);
188 stillNeedToSeeDoctype = false;
189 ready = true;
190 }
191 }
192
193 // need to eliminate original DOCTYPE if it exists
194 while (stillNeedToSeeDoctype && (current = original.read()) != -1) {
195 if (Character.isWhitespace((char) current)) {
196 after.append(current);
197 } else if (current == '<') {
198 int[] elementOrDeclOr = readUntilCloseCharIsReached();
199 if (elementOrDeclOr.length > 0) {
200 if (elementOrDeclOr[0] == '?') {
201 // PI
202 after.append('<');
203 after.append(elementOrDeclOr);
204 } else if (elementOrDeclOr[0] != '!') {
205 // first element
206 after.append('<');
207 after.append(elementOrDeclOr);
208 stillNeedToSeeDoctype = false;
209 } else {
210 // comment or doctype
211 IntegerBuffer b =
212 new IntegerBuffer(elementOrDeclOr.length);
213 b.append(elementOrDeclOr);
214 if (b.indexOf(DOCTYPE_INTS) == -1) {
215 after.append('<');
216 after.append(elementOrDeclOr);
217 } else {
218 // swallow old declaration
219 stillNeedToSeeDoctype = false;
220 }
221 }
222 } else {
223 after.append('<');
224 stillNeedToSeeDoctype = false;
225 }
226 } else {
227 after.append(current);
228 stillNeedToSeeDoctype = false;
229 }
230 }
231
232 beforeDoctype = before.size() > 0
233 ? new IntBufferReadable(before) : null;
234 afterDoctype = after.size() > 0
235 ? new IntBufferReadable(after) : null;
236 }
237
238 private int[] readUntilCloseCharIsReached() throws IOException {
239 IntegerBuffer i = new IntegerBuffer();
240 int intRead = -1;
241 int openCount = 1;
242 while (openCount > 0 && (intRead = original.read()) != -1) {
243 i.append(intRead);
244 if (intRead == '<') {
245 openCount++;
246 }
247 if (intRead == '>') {
248 openCount--;
249 }
250 }
251 return i.toIntArray();
252 }
253
254 private static class IntBufferReadable implements Readable {
255 private final int[] buf;
256 private int off;
257 IntBufferReadable(IntegerBuffer b) {
258 buf = b.toIntArray();
259 }
260 public int read() {
261 return off >= buf.length ? -1 : buf[off++];
262 }
263 }
264
265 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.Arrays;
39 import org.w3c.dom.Attr;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.NamedNodeMap;
42
43 /**
44 * More complex interface implementation that tests two elements for tag name
45 * and attribute name comparability.
46 * <br />Examples and more at
47 * <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
48 * @see DifferenceEngine#compareNodeList(NodeList, NodeList, int, DifferenceListener, ElementQualifier)
49 * @see Diff#overrideElementQualifier(ElementQualifier)
50 */
51 public class ElementNameAndAttributeQualifier extends ElementNameQualifier {
52 private static final String[] ALL_ATTRIBUTES = {"*"};
53
54 private final String[] qualifyingAttrNames;
55
56 /**
57 * No-args constructor: use all attributes from all elements to determine
58 * whether elements qualify for comparability
59 */
60 public ElementNameAndAttributeQualifier() {
61 this(ALL_ATTRIBUTES);
62 }
63
64 /**
65 * Simple constructor for a single qualifying attribute name
66 * @param attrName the value to use to qualify whether two elements can be
67 * compared further for differences
68 */
69 public ElementNameAndAttributeQualifier(String attrName) {
70 this(new String[] {attrName});
71 }
72
73 /**
74 * Extended constructor for multiple qualifying attribute names
75 * @param attrNames the array of values to use to qualify whether two
76 * elements can be compared further for differences
77 */
78 public ElementNameAndAttributeQualifier(String[] attrNames) {
79 this.qualifyingAttrNames = new String[attrNames.length];
80 System.arraycopy(attrNames, 0, qualifyingAttrNames, 0,
81 attrNames.length);
82 }
83
84 /**
85 * Determine whether two elements qualify for further Difference comparison.
86 * @param differenceEngine the DifferenceEngine instance wanting to
87 * determine if the elements are comparable
88 * @param control
89 * @param test
90 * @return true if the two elements qualify for further comparison based on
91 * both the superclass qualification (namespace URI and non- namespaced tag
92 * name), and the presence of qualifying attributes with the same values;
93 * false otherwise
94 */
95 public boolean qualifyForComparison(Element control, Element test) {
96 if (super.qualifyForComparison(control, test)) {
97 return areAttributesComparable(control, test);
98 }
99 return false;
100 }
101
102 /**
103 * Determine whether the qualifying attributes are present in both elements
104 * and if so whether their values are the same
105 * @param control
106 * @param test
107 * @return true if all qualifying attributes are present with the same
108 * values, false otherwise
109 */
110 protected boolean areAttributesComparable(Element control, Element test) {
111 String controlValue, testValue;
112 Attr[] qualifyingAttributes;
113 NamedNodeMap namedNodeMap = control.getAttributes();
114 if (matchesAllAttributes(qualifyingAttrNames)) {
115 qualifyingAttributes = new Attr[namedNodeMap.getLength()];
116 for (int n=0; n < qualifyingAttributes.length; ++n) {
117 qualifyingAttributes[n] = (Attr) namedNodeMap.item(n);
118 }
119 } else {
120 qualifyingAttributes = new Attr[qualifyingAttrNames.length];
121 for (int n=0; n < qualifyingAttrNames.length; ++n) {
122 qualifyingAttributes[n] = (Attr) namedNodeMap.getNamedItem(qualifyingAttrNames[n]);
123 }
124 }
125
126 String nsURI, name;
127 for (int i=0; i < qualifyingAttributes.length; ++i) {
128 if (qualifyingAttributes[i] != null) {
129 nsURI = qualifyingAttributes[i].getNamespaceURI();
130 controlValue = qualifyingAttributes[i].getNodeValue();
131 name = qualifyingAttributes[i].getName();
132 } else {
133 // cannot be "*" case
134 nsURI = controlValue = "";
135 name = qualifyingAttrNames[i];
136 }
137 if (nsURI == null || nsURI.length() == 0) {
138 testValue = test.getAttribute(name);
139 } else {
140 testValue = test.getAttributeNS(nsURI, qualifyingAttributes[i].getLocalName());
141 }
142 if (controlValue == null) {
143 if (testValue != null) {
144 return false;
145 }
146 } else {
147 if (!controlValue.equals(testValue)) {
148 return false;
149 }
150 }
151 }
152 return true;
153 }
154
155 private static boolean matchesAllAttributes(String[] attributes) {
156 return Arrays.equals(attributes, ALL_ATTRIBUTES);
157 }
158 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Element;
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41 import org.w3c.dom.Text;
42
43 /**
44 * More complex interface implementation that tests two elements for tag name
45 * and text content comparability.
46 * <br />Examples and more at
47 * <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
48 * @see DifferenceEngine#compareNodeList(NodeList, NodeList, int, DifferenceListener, ElementQualifier)
49 * @see Diff#overrideElementQualifier(ElementQualifier)
50 */
51 public class ElementNameAndTextQualifier extends ElementNameQualifier {
52 /**
53 * Determine whether two elements qualify for further Difference comparison.
54 * @param control
55 * @param test
56 * @return true if the two elements qualify for further comparison based on
57 * both the superclass qualification (namespace URI and non- namespaced tag
58 * name), and the qualification of the text nodes contained within the
59 * elements; false otherwise
60 */
61 public boolean qualifyForComparison(Element control, Element test) {
62 if (super.qualifyForComparison(control, test)) {
63 return similar(extractText(control), extractText(test));
64 }
65 return false;
66 }
67
68 /**
69 * Determine whether the text nodes contain similar values
70 * @param control
71 * @param test
72 * @return true if text nodes are similar, false otherwise
73 */
74 protected boolean similar(Text control, Text test) {
75 if (control == null) {
76 return test == null;
77 } else if (test == null) {
78 return false;
79 }
80 return control.getNodeValue().equals(test.getNodeValue());
81 }
82
83 /**
84 * Extract the normalized text from within an element
85 * @param fromElement
86 * @return extracted Text node (could be null)
87 */
88 protected Text extractText(Element fromElement) {
89 fromElement.normalize();
90 NodeList fromNodeList = fromElement.getChildNodes();
91 Node currentNode;
92 for (int i=0; i < fromNodeList.getLength(); ++i) {
93 currentNode = fromNodeList.item(i);
94 if (currentNode.getNodeType() == Node.TEXT_NODE) {
95 return (Text) currentNode;
96 }
97 }
98 return null;
99 }
100
101 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Element;
39 import org.w3c.dom.Node;
40
41 /**
42 * Simple interface implementation that tests two elements for name
43 * comparability. This class provides the default behaviour within a
44 * DifferenceEngine (for backwards compatibility)
45 * <br />Examples and more at
46 * <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
47 * @see DifferenceEngine#compareNodeList(NodeList, NodeList, int, DifferenceListener, ElementQualifier)
48 * @see Diff#overrideElementQualifier(ElementQualifier)
49 */
50 public class ElementNameQualifier implements ElementQualifier {
51 /**
52 * Determine whether two elements qualify for further Difference comparison.
53 * @param control
54 * @param test
55 * @return true if the two elements qualify for further comparison based on
56 * their similar namespace URI and non-namespaced tag name,
57 * false otherwise
58 */
59 public boolean qualifyForComparison(Element control, Element test) {
60 return control != null && test !=null
61 && equalsNamespace(control, test)
62 && getNonNamespacedNodeName(control).equals(getNonNamespacedNodeName(test));
63 }
64 /**
65 * Determine whether two nodes are defined by the same namespace URI
66 * @param control
67 * @param test
68 * @return true if the two nodes are both defined by the same namespace URI
69 * (including the default - empty - namespace), false otherwise
70 */
71 protected boolean equalsNamespace(Node control, Node test) {
72 String controlNS = control.getNamespaceURI();
73 String testNS = test.getNamespaceURI();
74 if (controlNS == null) {
75 return testNS == null;
76 }
77 return controlNS.equals(testNS);
78 }
79
80 /**
81 * Strip any namespace information off a node name
82 * @param node
83 * @return the localName if the node is namespaced, or the name otherwise
84 */
85 protected String getNonNamespacedNodeName(Node node) {
86 String name = node.getLocalName();
87 if (name == null) {
88 return node.getNodeName();
89 }
90 return name;
91 }
92
93 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Element;
39
40 /**
41 * Interface used by the DifferenceEngine class to determine which elements can
42 * be compared within a NodeList of child nodes.
43 *
44 * <br />Examples and more at
45 * <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
46 * @see DifferenceEngine#compareNodeList(NodeList, NodeList, int, DifferenceListener, ElementQualifier)
47 * @see Diff#overrideElementQualifier(ElementQualifier)
48 */
49
50 public interface ElementQualifier {
51 /**
52 * Determine whether two elements are comparable
53 * @param control an Element from the control XML NodeList
54 * @param test an Element from the test XML NodeList
55 * @return true if the elements are comparable, false otherwise
56 */
57 boolean qualifyForComparison(Element control, Element test);
58 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39 import java.io.Reader;
40 import java.io.StringReader;
41 import java.util.Enumeration;
42
43 import javax.swing.text.*;
44 import javax.swing.text.html.*;
45 import javax.swing.text.html.parser.*;
46
47 import org.w3c.dom.Document;
48
49 import org.xml.sax.ContentHandler;
50 import org.xml.sax.Attributes;
51 import org.xml.sax.SAXException;
52 import org.xml.sax.ext.LexicalHandler;
53 import org.xml.sax.helpers.AttributesImpl;
54
55 /**
56 * Build a DOM document from HTML content converting from 'plain' HTML into
57 * 'XHTML' along the way with the help of a TolerantSaxDocumentBuilder and
58 * the Swing html parser classes.
59 * This allows XML assertions to be made against badly formed HTML.
60 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
61 * @see TolerantSaxDocumentBuilder
62 */
63 public class HTMLDocumentBuilder {
64 protected final TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder;
65 protected final SwingEvent2SaxAdapter swingEvent2SaxAdapter;
66 private final StringBuffer traceBuffer;
67
68 /**
69 * Constructor
70 * @param tolerantSaxDocumentBuilder the instance that will receive SAX
71 * calls generated as the HTML is parsed and build up a DOM Document
72 */
73 public HTMLDocumentBuilder(
74 TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder) {
75 this.tolerantSaxDocumentBuilder = tolerantSaxDocumentBuilder;
76 this.swingEvent2SaxAdapter = new SwingEvent2SaxAdapter();
77 this.traceBuffer = new StringBuffer();
78 }
79
80 /**
81 * @return a DOM document parsed from the Reader via an SwingEvent2SaxAdapter
82 * and TolerantSaxBuilder.
83 * Not thread-safe!
84 * @see TolerantSaxDocumentBuilder
85 */
86 public Document parse(Reader reader) throws SAXException, IOException {
87 traceBuffer.delete(0, traceBuffer.length());
88 swingEvent2SaxAdapter.parse(reader, tolerantSaxDocumentBuilder);
89 traceBuffer.append(tolerantSaxDocumentBuilder.getTrace());
90 return tolerantSaxDocumentBuilder.getDocument();
91 }
92
93 /**
94 * @return a DOM document parsed from the String via an SwingEvent2SaxAdapter
95 * and TolerantSaxBuilder.
96 * Not thread-safe!
97 * @see TolerantSaxDocumentBuilder
98 */
99 public Document parse(String htmlString) throws SAXException, IOException {
100 return parse(new StringReader(htmlString));
101 }
102
103 /**
104 * @return the trace of events and / or warnings encountered during parsing
105 */
106 public String getTrace() {
107 return traceBuffer.toString();
108 }
109
110 /**
111 * Append to the log built up during parsing
112 * @param msg what to append
113 */
114 private void trace(String msg) {
115 traceBuffer.append(msg).append('\n');
116 }
117
118 /**
119 * Adapts Swing HTML callback messages to Sax equivalents, passing them
120 * to a Sax-aware ContentHandler.
121 */
122 public class SwingEvent2SaxAdapter extends HTMLEditorKit.ParserCallback {
123 private static final boolean IGNORE_HTML_CHAR_SET = true;
124 private final AttributesImpl attributes;
125 private final ParserDelegator delegator;
126 private boolean lastTagWasSimpleTag;
127 private ContentHandler saxContentHandler;
128 private SAXException firstUnhandledException;
129
130 /**
131 * Default constructor
132 */
133 public SwingEvent2SaxAdapter() {
134 this.attributes = new AttributesImpl();
135 this.delegator = new ParserDelegator();
136 }
137
138 /**
139 * Perform Swing-HTML-parse-event-to-Sax-event conversion
140 */
141 public void parse(Reader reader, ContentHandler saxContentHandler)
142 throws SAXException, IOException {
143 this.saxContentHandler = saxContentHandler;
144 preParse();
145 delegator.parse(reader, this, IGNORE_HTML_CHAR_SET);
146 postParse();
147 }
148
149 /**
150 * Equivalent to Sax <code>startDocument</code>
151 * @throws SAXException
152 */
153 private void preParse() throws SAXException {
154 firstUnhandledException = null;
155 saxContentHandler.startDocument();
156 }
157
158 /**
159 * Equivalent to Sax <code>endDocument</code>
160 * @throws SAXException if any SAXExceptions have occurred during
161 * parsing
162 */
163 private void postParse() throws SAXException {
164 try {
165 saxContentHandler.endDocument();
166 } catch (SAXException e) {
167 handleSAXException(e);
168 }
169 if (firstUnhandledException != null) {
170 throw firstUnhandledException;
171 }
172 }
173
174 /**
175 * Swing-HTML-parser template method, no ContentHandler equivalent
176 */
177 public void flush() throws javax.swing.text.BadLocationException {
178 }
179
180 /**
181 * Equivalent to Sax <code>characters</code>
182 */
183 public void handleText(char[] data, int pos) {
184 try {
185 int startPos;
186 if (lastTagWasSimpleTag) {
187 startPos = getStartIgnoringClosingSimpleTag(data);
188 } else {
189 startPos = 0;
190 }
191 if (startPos < data.length) {
192 saxContentHandler.characters(data, startPos,
193 data.length - startPos);
194 }
195 } catch (SAXException e) {
196 handleSAXException(e);
197 }
198 }
199
200 /**
201 * Adjusts the start offset into the character array for the fact that
202 * the Swing HTML parser doesn't handle simple tags with explicit
203 * closing angle brackets e.g. &lt;hr/&gt;
204 * @param data
205 * @return offset of actual character data into the array
206 */
207 private int getStartIgnoringClosingSimpleTag(char[] data) {
208 if (data[0] == '>') {
209 return 1;
210 }
211 return 0;
212 }
213
214 /**
215 * Equivalent to Sax LexicalHandler <code>comment</code> method.
216 * If the supplied ContentHandler is also an LexicalHandler then the
217 * cast will be made and the sax event passed on.
218 */
219 public void handleComment(char[] data, int pos) {
220 if (saxContentHandler instanceof LexicalHandler) {
221 try {
222 ((LexicalHandler)saxContentHandler).comment(data,
223 0, data.length);
224 } catch (SAXException e) {
225 handleSAXException(e);
226 }
227 } else {
228 trace("Unhandled comment " + new String(data));
229 }
230 }
231
232 /**
233 * Equivalent to Sax <code>startElement</code>
234 */
235 public void handleStartTag(javax.swing.text.html.HTML.Tag tag,
236 javax.swing.text.MutableAttributeSet attributeSet, int pos) {
237 try {
238 saxContentHandler.startElement("", "", tag.toString(),
239 convertToSaxAttributes(attributeSet));
240 } catch (SAXException e) {
241 handleSAXException(e);
242 }
243 lastTagWasSimpleTag = false;
244 }
245
246 /**
247 * Equivalent to Sax <code>endElement</code>
248 */
249 public void handleEndTag(javax.swing.text.html.HTML.Tag tag, int pos) {
250 try {
251 saxContentHandler.endElement("", "", tag.toString());
252 } catch (SAXException e) {
253 handleSAXException(e);
254 }
255 }
256
257 /**
258 * Equivalent to Sax <code>startElement</code> plus
259 * <code>endElement</code>
260 */
261 public void handleSimpleTag(javax.swing.text.html.HTML.Tag tag,
262 javax.swing.text.MutableAttributeSet attributeSet, int pos) {
263 handleStartTag(tag, attributeSet, pos);
264 handleEndTag(tag, pos);
265 lastTagWasSimpleTag = true;
266 }
267
268 /**
269 * Swing-HTML-parser template method, no ContentHandler equivalent.
270 * These errors are generally recoverable, so they are logged.
271 */
272 public void handleError(String errorMsg, int pos){
273 trace("HTML ERROR: " + errorMsg);
274 }
275
276 /**
277 * Simple conversion method.
278 * @param attributeSet
279 * @return Sax CDATA Attributes from the Swing MutableAttributeSet
280 */
281 private Attributes convertToSaxAttributes(
282 MutableAttributeSet attributeSet) {
283 Object attrName, attrValue;
284
285 attributes.clear();
286 for(Enumeration en = attributeSet.getAttributeNames();
287 en.hasMoreElements(); ) {
288 attrName = en.nextElement();
289 attrValue = attributeSet.getAttribute(attrName);
290 attributes.addAttribute("", "", attrName.toString(),
291 "CDATA", attrValue.toString());
292 }
293
294 return attributes;
295 }
296
297 /**
298 * Log an error from the ContentHandler for raising post-parse
299 */
300 private void handleSAXException(SAXException e) {
301 trace("SAX Error: " + e.getMessage());
302 if (firstUnhandledException==null) {
303 firstUnhandledException = e;
304 }
305 }
306 }
307
308 }
309
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Node;
39
40 /**
41 * Class to use when performing a Diff that only compares the
42 * structure of 2 pieces of XML, i.e. where the values of text
43 * and attribute nodes should be ignored.
44 * @see Diff#overrideDifferenceListener
45 */
46 public class IgnoreTextAndAttributeValuesDifferenceListener
47 implements DifferenceListener {
48 private static final int[] IGNORE_VALUES = new int[] {
49 DifferenceConstants.ATTR_VALUE.getId(),
50 DifferenceConstants.ATTR_VALUE_EXPLICITLY_SPECIFIED.getId(),
51 DifferenceConstants.TEXT_VALUE.getId()
52 };
53
54 private boolean isIgnoredDifference(Difference difference) {
55 int differenceId = difference.getId();
56 for (int i=0; i < IGNORE_VALUES.length; ++i) {
57 if (differenceId == IGNORE_VALUES[i]) {
58 return true;
59 }
60 }
61 return false;
62 }
63
64 /**
65 * @return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR to ignore
66 * differences in values of TEXT or ATTRIBUTE nodes,
67 * and RETURN_ACCEPT_DIFFERENCE to accept all other
68 * differences.
69 * @see DifferenceListener#differenceFound(Difference)
70 */
71 public int differenceFound(Difference difference) {
72 if (isIgnoredDifference(difference)) {
73 return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
74 } else {
75 return RETURN_ACCEPT_DIFFERENCE;
76 }
77 }
78
79 /**
80 * Do nothing
81 * @see DifferenceListener#skippedComparison(Node, Node)
82 */
83 public void skippedComparison(Node control, Node test) {
84 }
85
86 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * Utility constant class for JAXP-defined constants.
40 */
41 public final class JAXPConstants {
42
43 /**
44 * Utility constant class for JAXP Properties, typically used with
45 * {@link XMLReader#setProperty(String, Object)}.
46 *
47 */
48 public static final class Properties {
49
50 /**
51 * Property name for the Schema Language being used. As of JAXP 1.2,
52 * only W3C Schema are supported.
53 *
54 * @see XMLConstants#W3C_XML_SCHEMA_NS_URI
55 * @see http://java.sun.com/webservices/jaxp/change-requests-11.html
56 */
57 public static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
58
59 /**
60 * Property name for the Schema Location being used.
61 *
62 * @see http://java.sun.com/webservices/jaxp/change-requests-11.html
63 */
64 public static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
65
66 }
67 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Stefan Bodewig
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * Listener for callbacks from a {@link DifferenceEngine#compare
40 * DifferenceEngine comparison} that is notified on each and every
41 * comparision that resulted in a match.
42 */
43 public interface MatchTracker {
44 /**
45 * Receive notification that 2 match.
46 * @param match a Difference instance as defined in {@link
47 * DifferenceConstants DifferenceConstants} describing the test
48 * that matched and containing the detail of the nodes that have
49 * been compared
50 */
51 void matchFound(Difference difference);
52 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.Iterator;
39
40 /**
41 * Interface used by XpathEngine in order to map prefixes to namespace URIs.
42 *
43 * <p>This is modelled after javax.xml.namespace.NamespaceContext but
44 * reduced to our needs.</p>
45 */
46 public interface NamespaceContext {
47 /**
48 * Obtain the URI for a given prefix.
49 *
50 * <p>Unlike the method in javax.xml.namespace.NamespaceContext
51 * doesn't have to implement any special handling for predefined
52 * prefix values.</p>
53 *
54 * @return null if the prefix is unknown.
55 */
56 String getNamespaceURI(String prefix);
57
58 /**
59 * Get all prefixes of this context.
60 */
61 Iterator getPrefixes();
62 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Attr;
39 import org.w3c.dom.DocumentType;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.ProcessingInstruction;
42
43 /**
44 * Class for describing Nodes
45 */
46 public class NodeDescriptor implements XMLConstants {
47 protected static final String DOCUMENT_NODE_DESCRIPTION = "Document Node ";
48
49 /**
50 * Convert a Node into a simple String representation
51 * and append to StringBuffer
52 * @param buf
53 * @param aNode
54 */
55 public static void appendNodeDetail(StringBuffer buf, NodeDetail nodeDetail) {
56 appendNodeDetail(buf, nodeDetail.getNode(), true);
57 buf.append(" at ").append(nodeDetail.getXpathLocation());
58 }
59
60 private static void appendNodeDetail(StringBuffer buf, Node aNode,
61 boolean notRecursing) {
62 if (aNode==null) {
63 return;
64 }
65 if (notRecursing) {
66 buf.append(XMLConstants.OPEN_START_NODE);
67 }
68 switch (aNode.getNodeType()) {
69 case Node.ATTRIBUTE_NODE:
70 appendAttributeDetail(buf, aNode);
71 break;
72 case Node.ELEMENT_NODE:
73 appendElementDetail(buf, aNode, notRecursing);
74 break;
75 case Node.TEXT_NODE:
76 appendTextDetail(buf, aNode);
77 break;
78 case Node.CDATA_SECTION_NODE:
79 appendCdataSectionDetail(buf, aNode);
80 break;
81 case Node.COMMENT_NODE:
82 appendCommentDetail(buf, aNode);
83 break;
84 case Node.PROCESSING_INSTRUCTION_NODE:
85 appendProcessingInstructionDetail(buf, aNode);
86 break;
87 case Node.DOCUMENT_TYPE_NODE:
88 appendDocumentTypeDetail(buf, aNode);
89 break;
90 case Node.DOCUMENT_NODE:
91 appendDocumentDetail(buf);
92 break;
93 default:
94 buf.append("!--NodeType ").append(aNode.getNodeType())
95 .append(' ').append(aNode.getNodeName())
96 .append('/').append(aNode.getNodeValue())
97 .append("--");
98
99 }
100 if (notRecursing) {
101 buf.append(XMLConstants.CLOSE_NODE);
102 }
103 }
104
105 protected static void appendDocumentDetail(StringBuffer buf) {
106 buf.append(DOCUMENT_NODE_DESCRIPTION)
107 .append(XMLConstants.OPEN_START_NODE)
108 .append("...")
109 .append(XMLConstants.CLOSE_NODE);
110 }
111
112 protected static void appendDocumentTypeDetail(StringBuffer buf, Node aNode) {
113 DocumentType type = (DocumentType) aNode;
114 buf.append(XMLConstants.START_DOCTYPE).append(type.getName());
115 boolean hasNoPublicId = true;
116 if (type.getPublicId()!=null
117 && type.getPublicId().length() > 0) {
118 buf.append(" PUBLIC \"").append(type.getPublicId())
119 .append('"');
120 hasNoPublicId = false;
121 }
122 if (type.getSystemId()!=null
123 && type.getSystemId().length() > 0) {
124 if (hasNoPublicId) {
125 buf.append(" SYSTEM");
126 }
127 buf.append(" \"").append(type.getSystemId())
128 .append('"');
129 }
130 }
131
132 protected static void appendProcessingInstructionDetail(
133 StringBuffer buf, Node aNode) {
134 ProcessingInstruction instr = (ProcessingInstruction) aNode;
135 buf.append(XMLConstants.START_PROCESSING_INSTRUCTION)
136 .append(instr.getTarget())
137 .append(' ').append(instr.getData())
138 .append(XMLConstants.END_PROCESSING_INSTRUCTION);
139 }
140
141 protected static void appendCommentDetail(StringBuffer buf, Node aNode) {
142 buf.append(XMLConstants.START_COMMENT)
143 .append(aNode.getNodeValue())
144 .append(XMLConstants.END_COMMENT);
145 }
146
147 protected static void appendCdataSectionDetail(StringBuffer buf, Node aNode) {
148 buf.append(XMLConstants.START_CDATA)
149 .append(aNode.getNodeValue())
150 .append(XMLConstants.END_CDATA);
151 }
152
153 protected static void appendTextDetail(StringBuffer buf, Node aNode) {
154 appendNodeDetail(buf, aNode.getParentNode(), false);
155 buf.append(" ...").append(XMLConstants.CLOSE_NODE)
156 .append(aNode.getNodeValue())
157 .append(XMLConstants.OPEN_END_NODE);
158 appendNodeDetail(buf, aNode.getParentNode(), false);
159 }
160
161 protected static void appendElementDetail(StringBuffer buf, Node aNode,
162 boolean notRecursing) {
163 buf.append(aNode.getNodeName());
164 if (notRecursing) {
165 buf.append("...");
166 }
167 }
168
169 protected static void appendAttributeDetail(StringBuffer buf, Node aNode) {
170 appendNodeDetail(buf,
171 ((Attr)aNode).getOwnerElement(), false);
172 buf.append(' ')
173 .append(aNode.getNodeName()).append("=\"")
174 .append(aNode.getNodeValue()).append("\"...");
175 }
176 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit;
36
37 import org.w3c.dom.Node;
38
39 /**
40 * Parameter class for holding information about a <code>Node</code> within
41 * a Difference instance
42 * @see Difference#getControlNodeDetail
43 * @see Difference#getTestNodeDetail
44 */
45 public class NodeDetail {
46 private final String value;
47 private final Node node;
48 private final String xpathLocation;
49
50 /**
51 * Constructor for NodeDetail.
52 */
53 public NodeDetail(String value, Node node, String xpathLocation) {
54 this.value = value;
55 this.node = node;
56 this.xpathLocation = xpathLocation;
57 }
58
59
60 /**
61 * Returns the node.
62 * @return Node
63 */
64 public Node getNode() {
65 return node;
66 }
67
68 /**
69 * Returns the value.
70 * @return String
71 */
72 public String getValue() {
73 return value;
74 }
75
76 /**
77 * Returns the xpathLocation.
78 * @return String
79 */
80 public String getXpathLocation() {
81 return xpathLocation;
82 }
83
84 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.ByteArrayOutputStream;
39 import java.io.InputStream;
40 import java.io.IOException;
41 import java.util.Properties;
42 import javax.xml.transform.stream.StreamResult;
43 import org.w3c.dom.Node;
44
45 /**
46 * Adapter class to present the content of a DOM Node (e.g. a Document) as an
47 * InputStream using a DOM to Stream transformation.
48 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
49 */
50 public class NodeInputStream extends InputStream {
51 private final Node rootNode;
52 private final ByteArrayOutputStream nodeContentBytes;
53 private final Properties outputProperties;
54 private int atPos = 0;
55
56 /**
57 * Simple constructor
58 * @param rootNode the node to be presented as an input stream
59 */
60 public NodeInputStream(Node rootNode) {
61 this(rootNode, null);
62 }
63
64 /**
65 * Simple constructor
66 * @param rootNode the node to be presented as an input stream
67 */
68 public NodeInputStream(Node rootNode, Properties outputProperties) {
69 this.rootNode = rootNode;
70 nodeContentBytes = new ByteArrayOutputStream();
71 this.outputProperties = outputProperties;
72 }
73
74 /**
75 * Do the actual work of serializing the node to bytes
76 * @throws IOException if serialization goes awry
77 */
78 private void ensureContentAvailable() throws IOException {
79 if (nodeContentBytes.size() > 0) {
80 return;
81 }
82 try {
83 Transform serializeTransform = new Transform(rootNode);
84 if (outputProperties!=null) {
85 serializeTransform.setOutputProperties(outputProperties);
86 }
87 StreamResult byteResult = new StreamResult(nodeContentBytes);
88 serializeTransform.transformTo(byteResult);
89 } catch (Exception e) {
90 throw new IOException("Unable to serialize document to outputstream: "
91 + e.toString());
92 }
93 }
94
95 /**
96 * InputStream method
97 * @return byte as read
98 * @throws IOException
99 */
100 public int read() throws IOException {
101 ensureContentAvailable();
102 if (reallyAvailable()==0) {
103 return -1;
104 }
105 int contentByte = nodeContentBytes.toByteArray()[atPos];
106 atPos++;
107 return contentByte;
108 }
109
110 /**
111 * InputStream method
112 * Note that calling close allows a repeated read of the content
113 * @throws IOException
114 */
115 public void close() throws IOException {
116 atPos = 0;
117 }
118
119 /**
120 * InputStream method
121 * @return number of bytes available
122 */
123 public int available() throws IOException {
124 ensureContentAvailable();
125 return reallyAvailable();
126 }
127
128 /**
129 * @return really available
130 */
131 private int reallyAvailable() {
132 return nodeContentBytes.size() - atPos;
133 }
134 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39 import java.io.Reader;
40 import java.io.StringReader;
41
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.traversal.DocumentTraversal;
45 import org.w3c.dom.traversal.NodeFilter;
46 import org.w3c.dom.traversal.NodeIterator;
47 import org.xml.sax.InputSource;
48 import org.xml.sax.SAXException;
49
50 /**
51 * Encapsulation of the Node-by-Node testing of a DOM Document
52 * Uses a nodetype-specific <code>NodeFilter</code> to pass the DOM Nodes
53 * to a NodeTester instance that performs the acual Node validation.
54 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.
55 * sourceforge.net</a>
56 * @see NodeTester
57 */
58 public class NodeTest {
59 private final DocumentTraversal documentTraversal;
60 private final Node rootNode;
61
62 /**
63 * Construct a NodeTest for the DOM built using the String and JAXP
64 */
65 public NodeTest(String xmlString)
66 throws SAXException, IOException {
67 this(new StringReader(xmlString));
68 }
69
70 /**
71 * Construct a NodeTest for the DOM built using the Reader and JAXP
72 */
73 public NodeTest(Reader reader) throws SAXException,
74 IOException {
75 this(XMLUnit.buildDocument(XMLUnit.newControlParser(), reader));
76 }
77
78 /**
79 * Construct a NodeTest for the DOM built using the InputSource.
80 */
81 public NodeTest(InputSource src) throws SAXException,
82 IOException {
83 this(XMLUnit.buildDocument(XMLUnit.newControlParser(), src));
84 }
85
86 /**
87 * Construct a NodeTest for the specified Document
88 * @exception IllegalArgumentException if the Document does not support the DOM
89 * DocumentTraversal interface (most DOM implementations should provide this
90 * support)
91 */
92 public NodeTest(Document document) {
93 this(getDocumentTraversal(document),
94 document.getDocumentElement());
95 }
96
97 /**
98 * Try to cast a Document into a DocumentTraversal
99 * @param document
100 * @return DocumentTraversal interface if the DOM implementation supports it
101 */
102 private static DocumentTraversal getDocumentTraversal(Document document) {
103 try {
104 return (DocumentTraversal) document;
105 } catch (ClassCastException e) {
106 throw new IllegalArgumentException("DOM Traversal not supported by "
107 + document.getImplementation().getClass().getName()
108 + ". To use this class you will need to switch to a DOM implementation that supports Traversal.");
109 }
110 }
111
112 /**
113 * Construct a NodeTest using the specified DocumentTraversal, starting at
114 * the specified root node
115 */
116 public NodeTest(DocumentTraversal documentTraversal, Node rootNode) {
117 this.documentTraversal = documentTraversal;
118 this.rootNode = rootNode;
119 }
120
121 /**
122 * Does this NodeTest pass using the specified NodeTester instance?
123 * @param tester
124 * @param singleNodeType note <code>Node.ATTRIBUTE_NODE</code> is not
125 * exposed by the DocumentTraversal node iterator unless the root node
126 * is itself an attribute - so a NodeTester that needs to test attributes
127 * should obtain those attributes from <code>Node.ELEMENT_NODE</code>
128 * nodes
129 * @exception NodeTestException if test fails
130 */
131 public void performTest(NodeTester tester, short singleNodeType)
132 throws NodeTestException {
133 performTest(tester, new short[] {singleNodeType});
134 }
135
136 /**
137 * Does this NodeTest pass using the specified NodeTester instance?
138 * @param tester
139 * @param nodeTypes note <code>Node.ATTRIBUTE_NODE</code> is not
140 * exposed by the DocumentTraversal node iterator unless the root node
141 * is itself an attribute - so a NodeTester that needs to test attributes
142 * should obtain those attributes from <code>Node.ELEMENT_NODE</code>
143 * nodes instead
144 * @exception NodeTestException if test fails
145 */
146 public void performTest(NodeTester tester, short[] nodeTypes)
147 throws NodeTestException {
148 NodeIterator iter = documentTraversal.createNodeIterator(rootNode,
149 NodeFilter.SHOW_ALL, new NodeTypeNodeFilter(nodeTypes), true);
150
151 for (Node nextNode = iter.nextNode(); nextNode != null;
152 nextNode = iter.nextNode()) {
153 tester.testNode(nextNode, this);
154 }
155 tester.noMoreNodes(this);
156 }
157
158 /**
159 * Node type specific Node Filter: accepts Nodes of those types specified
160 * in constructor, rejects all others
161 */
162 private static class NodeTypeNodeFilter implements NodeFilter {
163 private final short[] nodeTypes;
164
165 /**
166 * Construct filter for specific node types
167 * @param nodeTypes note <code>Node.ATTRIBUTE_NODE</code> is not
168 * exposed by the DocumentTraversal node iterator unless the root node
169 * is itself an attribute - so a NodeTester that needs to test attributes
170 * should obtain those attributes from <code>Node.ELEMENT_NODE</code>
171 * nodes
172 */
173 public NodeTypeNodeFilter(short[] nodeTypes) {
174 this.nodeTypes = nodeTypes;
175 }
176
177 /**
178 * NodeFilter method.
179 * @param aNode
180 * @return
181 */
182 public short acceptNode(Node aNode) {
183 if (acceptNodeType(aNode.getNodeType())) {
184 return NodeFilter.FILTER_ACCEPT;
185 }
186 return NodeFilter.FILTER_REJECT;
187 }
188
189 /**
190 * Does this instance accept nodes with the node type value
191 * @param shortVal
192 * @return
193 */
194 private boolean acceptNodeType(short shortVal) {
195 for (int i=0; i < nodeTypes.length; ++i) {
196 if (nodeTypes[i] == shortVal) {
197 return true;
198 }
199 }
200 return false;
201 }
202 }
203 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Node;
39
40 /**
41 * Thrown by a NodeTest that fails.
42 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
43 * @see NodeTest
44 */
45 public class NodeTestException extends Exception {
46 private transient final Node node;
47
48 /**
49 * Constructor for specific node and message
50 * @param message
51 * @param node
52 */
53 public NodeTestException(String message, Node node) {
54 super(message);
55 this.node = node;
56 }
57
58 /**
59 * Constructor for message only
60 * @param message
61 */
62 public NodeTestException(String message) {
63 this(message, null);
64 }
65
66 /**
67 * @return true if a node was passed to constructor
68 */
69 public boolean hasNode() {
70 return node != null;
71 }
72
73 /**
74 * @return the node passed to constructor, or null if no node was passed
75 */
76 public Node getNode() {
77 return node;
78 }
79
80 /**
81 * @return the exception message and node information if available
82 */
83 public String getMessage() {
84 StringBuffer stringBuffer = new StringBuffer(super.getMessage());
85 if (hasNode()) {
86 stringBuffer.append(' ')
87 .append(getNode().toString());
88 }
89 return stringBuffer.toString();
90 }
91 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Node;
39
40 /**
41 * Perform Node-by-Node validation of a DOM Document.
42 * Nodes are supplied to <code>testNode</code> method by a NodeTest instance,
43 * and after all the nodes in the NodeTest have been supplied the
44 * <code>noMoreNodes</code> method is called.
45 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
46 * @see NodeTest
47 */
48 public interface NodeTester {
49 /**
50 * Validate a single Node
51 * @param aNode
52 * @param forTest
53 * @exception NodeTestException if the node fails the test
54 */
55 void testNode(Node aNode, NodeTest forTest) throws NodeTestException ;
56
57 /**
58 * Validate that the Nodes passed one-by-one to the <code>testNode</code>
59 * method were all the Nodes expected.
60 * @param forTest
61 * @exception NodeTestException if this instance was expecting more nodes
62 */
63 void noMoreNodes(NodeTest forTest) throws NodeTestException ;
64 }
0 /*
1 *****************************************************************
2 Copyright (c) 2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * Since javax.xml.namespace.QName is not present prior to Java5, this
40 * is XMLUnit's own abstraction.
41 */
42 public final class QualifiedName {
43 private final String namespaceUri;
44 private final String localName;
45
46 public QualifiedName(String localName) {
47 this(XMLConstants.NULL_NS_URI, localName);
48 }
49
50 public QualifiedName(String namespaceUri, String localName) {
51 if (localName == null) {
52 throw new IllegalArgumentException("localName must not be null");
53 }
54 this.namespaceUri =
55 namespaceUri == null ? XMLConstants.NULL_NS_URI : namespaceUri;
56 this.localName = localName;
57 }
58
59 public String getNamespaceURI() {
60 return namespaceUri;
61 }
62
63 public String getLocalName() {
64 return localName;
65 }
66
67 public int hashCode() {
68 return 7 * namespaceUri.hashCode() + localName.hashCode();
69 }
70
71 public boolean equals(Object o) {
72 if (!(o instanceof QualifiedName)) {
73 return false;
74 }
75 QualifiedName other = (QualifiedName) o;
76 return namespaceUri.equals(other.namespaceUri)
77 && localName.equals(other.localName);
78 }
79
80 /**
81 * Parses strings of the form "{NS-URI}LOCAL-NAME" or "prefix:localName" as QualifiedNames.
82 *
83 * <p>When using the prefix-version the prefix must be defined
84 * inside the current NamespaceContext.</p>
85 *
86 * @see XMLUnit#setXpathNamespaceContext
87 */
88 public static QualifiedName valueOf(String value) {
89 return valueOf(value, XMLUnit.getXpathNamespaceContext());
90 }
91
92 /**
93 * Represents the QualifiedName as {NS-URI}LOCAL-NAME.
94 *
95 * <p>If the NS-URI is equal to NULL_NS_URI only the local name is returned.</p>
96 */
97 public String toString() {
98 return XMLConstants.NULL_NS_URI.equals(namespaceUri) ?
99 localName : "{" + namespaceUri + "}" + localName;
100 }
101
102 /**
103 * Parses strings of the form "{NS-URI}LOCAL-NAME" or "prefix:localName" as QualifiedNames.
104 *
105 * <p>When using the prefix-version the prefix must be defined
106 * inside the NamespaceContext given as argument.</p>
107 */
108 public static QualifiedName valueOf(String value, NamespaceContext ctx) {
109 if (value == null) {
110 throw new IllegalArgumentException("value must not be null");
111 }
112 int colon = value.indexOf(':');
113 int closingBrace = value.indexOf('}');
114 boolean qnameToStringStyle = value.startsWith("{") && closingBrace > 0;
115 if (!qnameToStringStyle && colon < 0) {
116 return new QualifiedName(value); // null namespace
117 }
118 return qnameToStringStyle ? parseQNameToString(value, closingBrace)
119 : parsePrefixFormat(value, colon, ctx);
120 }
121
122 private static QualifiedName parseQNameToString(String value, int closingBrace) {
123 if (closingBrace + 1 == value.length()) {
124 throw new IllegalArgumentException("localName must not be empty in "
125 + value);
126 }
127 return new QualifiedName(value.substring(1, closingBrace),
128 value.substring(closingBrace + 1));
129 }
130
131 private static QualifiedName parsePrefixFormat(String value, int colon,
132 NamespaceContext ctx) {
133 if (colon + 1 == value.length()) {
134 throw new IllegalArgumentException("localName must not be empty in "
135 + value);
136 }
137 if (ctx == null) {
138 throw new IllegalArgumentException("Cannot parse " + value
139 + " without a NamespaceContext");
140 }
141 String prefix = value.substring(0, colon);
142 String nsUri = ctx.getNamespaceURI(prefix);
143 if (nsUri == null) {
144 throw new IllegalArgumentException(prefix + " is unknown to "
145 + "NamespaceContext");
146 }
147 return new QualifiedName(nsUri, value.substring(colon + 1));
148 }
149 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.Map;
42
43 /**
44 * Implementation of NamespaceContext that's backed by a map.
45 */
46 public class SimpleNamespaceContext implements NamespaceContext {
47 /* prefix -> NS URI */
48 private final Map/*<String, String>*/ prefixMap;
49
50 /**
51 * An empty context containing no prefixes at all.
52 */
53 public static final SimpleNamespaceContext EMPTY_CONTEXT =
54 new SimpleNamespaceContext(Collections.EMPTY_MAP);
55
56 /**
57 * Creates a NamespaceContext backed by the given map.
58 *
59 * <p>Copies the map, changes made to the given map after calling
60 * the constructor are not reflected into the
61 * NamespaceContext.</p>
62 *
63 * @param prefixMap maps prefix to Namespace URI
64 */
65 public SimpleNamespaceContext(Map prefixMap) {
66 this.prefixMap = new HashMap(prefixMap);
67 }
68
69 public String getNamespaceURI(String prefix) {
70 return (String) prefixMap.get(prefix);
71 }
72
73 public Iterator getPrefixes() {
74 return prefixMap.keySet().iterator();
75 }
76 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XpathException;
40
41 import java.io.StringReader;
42 import java.io.StringWriter;
43 import java.util.Iterator;
44 import javax.xml.transform.ErrorListener;
45 import javax.xml.transform.Transformer;
46 import javax.xml.transform.TransformerException;
47 import javax.xml.transform.TransformerFactory;
48 import javax.xml.transform.Result;
49 import javax.xml.transform.dom.DOMResult;
50 import javax.xml.transform.dom.DOMSource;
51 import javax.xml.transform.stream.StreamResult;
52 import javax.xml.transform.stream.StreamSource;
53 import org.w3c.dom.Document;
54 import org.w3c.dom.Node;
55 import org.w3c.dom.NodeList;
56
57 /**
58 * Simple class for accessing the Nodes matched by an Xpath expression, or
59 * evaluating the String value of an Xpath expression.
60 * Uses a <code>copy-of</code> or <code>value-of</code> XSL template (as
61 * appropriate) to execute the Xpath.
62 * This is not an efficient method for accessing XPaths but it is portable
63 * across underlying transform implementations. (Yes I know Jaxen is too, but
64 * this approach seemed to be the simplest thing that could possibly work...)
65 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
66 */
67 public class SimpleXpathEngine implements XpathEngine, XSLTConstants {
68
69 private NamespaceContext ctx = SimpleNamespaceContext.EMPTY_CONTEXT;
70
71 /**
72 * What every XSL transform needs
73 * @return
74 */
75 private StringBuffer getXSLTBase() {
76 StringBuffer result = new StringBuffer(XML_DECLARATION)
77 .append(XMLUnit.getXSLTStart());
78 String tmp = result.toString();
79 int close = tmp.lastIndexOf('>');
80 if (close == -1) {
81 close = tmp.length();
82 }
83 result.insert(close, getNamespaceDeclarations());
84 return result;
85 }
86
87 /**
88 * @param select an xpath syntax <code>select</code> expression
89 * @return the <code>copy-of</code> transformation
90 */
91 private String getCopyTransformation(String select) {
92 return getXSLTBase()
93 .append("<xsl:preserve-space elements=\"*\"/>")
94 .append("<xsl:output method=\"xml\" version=\"1.0\" encoding=\"UTF-8\"/>")
95 .append("<xsl:template match=\"/\">")
96 .append("<xpathResult>")
97 .append("<xsl:apply-templates select=\"").append(select)
98 .append("\" mode=\"result\"/>")
99 .append("</xpathResult>")
100 .append("</xsl:template>")
101 .append("<xsl:template match=\"*\" mode=\"result\">")
102 .append(" <xsl:copy-of select=\".\"/>")
103 .append("</xsl:template>")
104 .append("</xsl:stylesheet>")
105 .toString();
106 }
107
108 /**
109 * @param select an xpath syntax <code>select</code> expression
110 * @return the <code>value-of</code> transformation
111 */
112 private String getValueTransformation(String select) {
113 return getXSLTBase()
114 .append("<xsl:output method=\"text\"/>")
115 .append("<xsl:template match=\"/\">")
116 .append(" <xsl:value-of select=\"").append(select).append("\"/>")
117 .append("</xsl:template>")
118 .append("</xsl:stylesheet>")
119 .toString();
120 }
121
122 /**
123 * Perform the actual transformation work required
124 * @param xslt
125 * @param document
126 * @param result
127 * @throws XpathException
128 * @throws TransformerException
129 * @throws ConfigurationException
130 */
131 private void performTransform(String xslt, Document document,
132 Result result)
133 throws TransformerException, ConfigurationException, XpathException {
134 try {
135 StreamSource source = new StreamSource(new StringReader(xslt));
136 TransformerFactory tf = XMLUnit.newTransformerFactory();
137 ErrorListener el = new ErrorListener() {
138 public void error(TransformerException ex)
139 throws TransformerException {
140 // any error in our simple stylesheet must be fatal
141 throw ex;
142 }
143 public void fatalError(TransformerException ex)
144 throws TransformerException {
145 throw ex;
146 }
147 public void warning(TransformerException ex) {
148 // there shouldn't be any warning
149 ex.printStackTrace();
150 }
151 };
152 tf.setErrorListener(el);
153 Transformer transformer = tf.newTransformer(source);
154 // Issue 1985229 says Xalan-J 2.7.0 may return null for
155 // illegal input
156 if (transformer == null) {
157 throw new XpathException("failed to obtain an XSLT transformer"
158 + " for XPath expression.");
159 }
160 transformer.setErrorListener(el);
161 transformer.transform(new DOMSource(document), result);
162 } catch (javax.xml.transform.TransformerConfigurationException ex) {
163 throw new ConfigurationException(ex);
164 }
165 }
166
167 /**
168 * Testable method to execute the copy-of transform and return the root
169 * node of the resulting Document.
170 * @param select
171 * @param document
172 * @throws ConfigurationException
173 * @throws TransformerException
174 * @return the root node of the Document created by the copy-of transform.
175 */
176 protected Node getXPathResultNode(String select, Document document)
177 throws ConfigurationException, TransformerException, XpathException {
178 return getXPathResultAsDocument(select, document).getDocumentElement();
179 }
180
181 /**
182 * Execute the copy-of transform and return the resulting Document.
183 * Used for XMLTestCase comparison
184 * @param select
185 * @param document
186 * @throws ConfigurationException
187 * @throws TransformerException
188 * @return the Document created by the copy-of transform.
189 */
190 protected Document getXPathResultAsDocument(String select,
191 Document document)
192 throws ConfigurationException, TransformerException, XpathException {
193 DOMResult result = new DOMResult();
194 performTransform(getCopyTransformation(select), document, result);
195 return (Document) result.getNode();
196 }
197
198 /**
199 * Execute the specified xpath syntax <code>select</code> expression
200 * on the specified document and return the list of nodes (could have
201 * length zero) that match
202 * @param select
203 * @param document
204 * @return list of matching nodes
205 */
206 public NodeList getMatchingNodes(String select, Document document)
207 throws ConfigurationException, XpathException {
208 try {
209 return getXPathResultNode(select, document).getChildNodes();
210 } catch (TransformerException ex) {
211 throw new XpathException("Failed to apply stylesheet", ex);
212 }
213 }
214
215 /**
216 * Evaluate the result of executing the specified xpath syntax
217 * <code>select</code> expression on the specified document
218 * @param select
219 * @param document
220 * @return evaluated result
221 */
222 public String evaluate(String select, Document document)
223 throws ConfigurationException, XpathException {
224 try {
225 StringWriter writer = new StringWriter();
226 StreamResult result = new StreamResult(writer);
227 performTransform(getValueTransformation(select), document, result);
228 return writer.toString();
229 } catch (TransformerException ex) {
230 throw new XpathException("Failed to apply stylesheet", ex);
231 }
232 }
233
234 public void setNamespaceContext(NamespaceContext ctx) {
235 this.ctx = ctx;
236 }
237
238 /**
239 * returns namespace declarations for all namespaces known to the
240 * current context.
241 */
242 private String getNamespaceDeclarations() {
243 StringBuffer nsDecls = new StringBuffer();
244 String quoteStyle = "'";
245 for (Iterator keys = ctx.getPrefixes(); keys.hasNext(); ) {
246 String prefix = (String) keys.next();
247 String uri = ctx.getNamespaceURI(prefix);
248 if (uri == null) {
249 continue;
250 }
251 // this shouldn't have happened, but better safe than sorry
252 if (prefix == null) {
253 prefix = "";
254 }
255
256 if (uri.indexOf('\'') != -1) {
257 quoteStyle = "\"";
258 }
259 nsDecls.append(' ').append(XMLNS_PREFIX);
260 if (prefix.length() > 0) {
261 nsDecls.append(':');
262 }
263 nsDecls.append(prefix).append('=')
264 .append(quoteStyle).append(uri).append(quoteStyle)
265 .append(' ');
266 }
267 return nsDecls.toString();
268 }
269 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.ParserConfigurationException;
40
41 import org.w3c.dom.Comment;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.Node;
45 import org.w3c.dom.ProcessingInstruction;
46 import org.w3c.dom.Text;
47
48 import org.xml.sax.Attributes;
49 import org.xml.sax.Locator;
50 import org.xml.sax.SAXException;
51 import org.xml.sax.ext.LexicalHandler;
52 import org.xml.sax.helpers.DefaultHandler;
53
54 /**
55 * Uses Sax events from the <code>ContentHandler</code> and
56 * <code>LexicalHandler</code> interfaces to build a DOM document in a tolerant
57 * fashion -- it can cope with start tags without end tags, and end tags without
58 * start tags for example.
59 * Although this subverts the idea of XML being well-formed, it is intended
60 * for use with HTML pages so that they can be transformed into DOM
61 * trees, without being XHTML to start with.
62 * Note that this class currently does not handle entity, DTD or CDATA tags.
63 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
64 * @see HTMLDocumentBuilder#parse
65 */
66 public class TolerantSaxDocumentBuilder
67 extends DefaultHandler implements LexicalHandler {
68 private final DocumentBuilder documentBuilder;
69 private final StringBuffer traceBuffer;
70 private Document currentDocument;
71 private Element currentElement;
72
73 /**
74 * Constructor for specific JAXP parser
75 * @param documentBuilder the JAXP parser to use to construct an empty
76 * DOM document that will be built up with SAX calls
77 * @throws ParserConfigurationException
78 */
79 public TolerantSaxDocumentBuilder(DocumentBuilder documentBuilder)
80 throws ParserConfigurationException {
81 this.documentBuilder = documentBuilder;
82 this.traceBuffer = new StringBuffer();
83 }
84
85 /**
86 * @return the Document built up through the Sax calls
87 */
88 public Document getDocument() {
89 return currentDocument;
90 }
91
92 /**
93 * @return the trace of Sax calls that were used to build up the Document
94 */
95 public String getTrace() {
96 return traceBuffer.toString();
97 }
98
99 /**
100 * ContentHandler method
101 * @throws SAXException
102 */
103 public void startDocument() throws SAXException {
104 traceBuffer.delete(0, traceBuffer.length());
105 trace("startDocument");
106 currentDocument = documentBuilder.newDocument();
107 currentElement = null;
108 }
109
110 /**
111 * ContentHandler method
112 * @throws SAXException
113 */
114 public void endDocument() throws SAXException {
115 trace("endDocument");
116 }
117
118 /**
119 * ContentHandler method.
120 */
121 public void characters(char[] data, int start, int length) {
122 if (length >= 0) {
123 String characterData = new String(data, start, length);
124 trace("characters:" + characterData);
125 if (currentElement == null) {
126 warn("Can't append text node to null currentElement");
127 } else {
128 Text textNode = currentDocument.createTextNode(characterData);
129 currentElement.appendChild(textNode);
130 }
131 } else {
132 warn("characters called with negative length");
133 }
134 }
135
136 /**
137 * ContentHandler method
138 * @throws SAXException
139 */
140 public void startElement(String namespaceURI, String localName,
141 String qName, Attributes atts) throws SAXException {
142 trace("startElement:" + localName + "~" + qName);
143 Element newElement = createElement(namespaceURI, qName, atts);
144 appendNode(newElement);
145 currentElement = newElement;
146 }
147
148 /**
149 * ContentHandler method
150 * @throws SAXException
151 */
152 public void endElement(String namespaceURI, String localName,
153 String qName) throws SAXException {
154 trace("endElement:" + localName + "~" + qName);
155 if (currentElement==null) {
156 warn(qName + ": endElement before any startElement");
157 return;
158 }
159
160 Node parentNode = null;
161 boolean atDocumentRoot = false, foundTagToEnd = false;
162 Element startElement = currentElement;
163
164 while (!(foundTagToEnd || atDocumentRoot)) {
165 parentNode = currentElement.getParentNode();
166
167 if (parentNode.getNodeType()==Node.ELEMENT_NODE) {
168 foundTagToEnd = isElementMatching(currentElement, qName);
169 currentElement = (Element) parentNode;
170 } else if (parentNode.getNodeType()==Node.DOCUMENT_NODE) {
171 atDocumentRoot = true;
172 if (startElement==currentDocument.getDocumentElement()) {
173 foundTagToEnd = isElementMatching(startElement, qName);
174 } else {
175 currentElement = startElement;
176 }
177 } else {
178 throw new IllegalArgumentException("Closing element " + qName
179 + ": expecting a parent ELEMENT_NODE but found " + parentNode);
180 }
181 }
182 if (!foundTagToEnd) {
183 warn(qName + ": endElement does not match startElement!");
184 }
185 }
186
187 private boolean isElementMatching(Element anElement, String qname) {
188 return anElement.getNodeName()!=null
189 && anElement.getNodeName().equals(qname);
190 }
191
192 /**
193 * Unhandled ContentHandler method
194 * @throws SAXException
195 */
196 public void endPrefixMapping(String prefix) throws SAXException {
197 unhandled("endPrefixMapping");
198 }
199
200 /**
201 * Unhandled ContentHandler method
202 * @throws SAXException
203 */
204 public void ignorableWhitespace (char ch[], int start, int length)
205 throws SAXException {
206 unhandled("ignorableWhitespace");
207 }
208
209 /**
210 * ContentHandler method
211 * @throws SAXException
212 */
213 public void processingInstruction(String target, String data)
214 throws SAXException {
215 trace("processingInstruction");
216 ProcessingInstruction instruction =
217 currentDocument.createProcessingInstruction(target, data);
218 appendNode(instruction);
219 }
220
221 /**
222 * Unhandled ContentHandler method
223 */
224 public void setDocumentLocator (Locator locator) {
225 unhandled("setDocumentLocator");
226 }
227
228 /**
229 * Unhandled ContentHandler method
230 * @throws SAXException
231 */
232 public void skippedEntity (String name) throws SAXException {
233 unhandled("skippedEntity");
234 }
235
236 /**
237 * Unhandled ContentHandler method
238 * @throws SAXException
239 */
240 public void startPrefixMapping (String prefix, String uri)
241 throws SAXException {
242 unhandled("startPrefixMapping");
243 }
244
245 /**
246 * Unhandled LexicalHandler method.
247 * DOM currently doesn't allow DTD to be retrofitted onto a Document.
248 * @throws SAXException
249 */
250 public void startDTD (String name, String publicId,
251 String systemId) throws SAXException {
252 unhandled("startDTD");
253 }
254
255 /**
256 * Unhandled LexicalHandler method
257 * @throws SAXException
258 */
259 public void endDTD ()
260 throws SAXException {
261 unhandled("endDTD");
262 }
263
264 /**
265 * Unhandled LexicalHandler method
266 * @throws SAXException
267 */
268 public void startEntity (String name)
269 throws SAXException {
270 unhandled("startEntity");
271 }
272
273 /**
274 * Unhandled LexicalHandler method
275 * @throws SAXException
276 */
277 public void endEntity (String name)
278 throws SAXException {
279 unhandled("endEntity");
280 }
281
282 /**
283 * Unhandled LexicalHandler method
284 * @throws SAXException
285 */
286 public void startCDATA ()
287 throws SAXException {
288 unhandled("startCDATA");
289 }
290
291 /**
292 * Unhandled LexicalHandler method
293 * @throws SAXException
294 */
295 public void endCDATA ()
296 throws SAXException {
297 unhandled("endCDATA");
298 }
299
300 /**
301 * LexicalHandler method
302 * @throws SAXException
303 */
304 public void comment(char ch[], int start, int length)
305 throws SAXException {
306 String commentText = new String(ch, start, length);
307 trace("comment:" + commentText);
308 Comment comment = currentDocument.createComment(commentText);
309 appendNode(comment);
310 }
311
312 /**
313 * Log an unhandled ContentHandler or LexicalHandler method
314 * @param method
315 */
316 private void unhandled(String method) {
317 trace("Unhandled callback: " + method);
318 }
319
320 /**
321 * Log a warning about badly formed markup
322 * @param msg
323 */
324 private void warn(String msg) {
325 trace("WARNING: " + msg);
326 }
327
328 /**
329 * Log a handled ContentHandler or LexicalHandler method
330 * for tracing / debug purposes
331 * @param method
332 */
333 private void trace(String method) {
334 traceBuffer.append(method).append('\n');
335 }
336
337 /**
338 * Create a DOM Element for insertion into the current document
339 * @param namespaceURI
340 * @param qName
341 * @param attributes
342 * @return the created Element
343 */
344 private Element createElement(String namespaceURI, String qName,
345 Attributes attributes) {
346 Element newElement = currentDocument.createElement(qName);
347
348 if (namespaceURI != null && namespaceURI.length() > 0) {
349 newElement.setPrefix(namespaceURI);
350 }
351
352 for(int i = 0; attributes != null && i < attributes.getLength(); ++i) {
353 newElement.setAttribute(attributes.getQName(i),
354 attributes.getValue(i));
355 }
356
357 return newElement;
358 }
359
360 /**
361 * Append a node to the current document or the current element in the document
362 * @param appendNode
363 */
364 private void appendNode(Node appendNode) {
365 if (currentElement==null) {
366 currentDocument.appendChild(appendNode);
367 } else {
368 currentElement.appendChild(appendNode);
369 }
370 }
371 }
372
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
40
41 import java.io.File;
42 import java.io.StringReader;
43 import java.io.StringWriter;
44 import java.net.MalformedURLException;
45 import java.util.Properties;
46
47 import javax.xml.transform.ErrorListener;
48 import javax.xml.transform.Result;
49 import javax.xml.transform.Source;
50 import javax.xml.transform.Transformer;
51 import javax.xml.transform.TransformerException;
52 import javax.xml.transform.TransformerFactory;
53 import javax.xml.transform.URIResolver;
54 import javax.xml.transform.dom.DOMSource;
55 import javax.xml.transform.dom.DOMResult;
56 import javax.xml.transform.sax.SAXSource;
57 import javax.xml.transform.stream.StreamResult;
58 import javax.xml.transform.stream.StreamSource;
59 import org.xml.sax.InputSource;
60 import org.w3c.dom.Document;
61 import org.w3c.dom.Node;
62
63 /**
64 * Handy wrapper for an XSLT transformation performed using JAXP/Trax.
65 * Note that transformation is not actually performed until a call to
66 * <code>getResultXXX</code> method, and Templates are not used.
67 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
68 */
69 public class Transform {
70 private static final File PWD = new File(".");
71
72 private final Source inputSource;
73 private final Transformer transformer;
74
75 /**
76 * Create a transformation using String input XML and String stylesheet
77 * @param input
78 * @param stylesheet
79 */
80 public Transform(String input, String stylesheet) {
81 this(new StreamSource(new StringReader(input)),
82 new StreamSource(new StringReader(stylesheet)));
83 }
84
85 /**
86 * Create a transformation using String input XML and stylesheet in a File
87 * @param input
88 * @param stylesheet
89 */
90 public Transform(String input, File stylesheet) {
91 this(new StreamSource(new StringReader(input)),
92 new StreamSource(stylesheet));
93 }
94
95 /**
96 * Create a transformation using InputSource input XML and
97 * InputSource stylesheet
98 * @param input
99 * @param stylesheet
100 */
101 public Transform(InputSource input, InputSource stylesheet) {
102 this(new SAXSource(input), new SAXSource(stylesheet));
103 }
104
105 /**
106 * Create a transformation using InputSource input XML and
107 * stylesheet in a File
108 * @param input
109 * @param stylesheet
110 */
111 public Transform(InputSource input, File stylesheet) {
112 this(new SAXSource(input), new StreamSource(stylesheet));
113 }
114
115 /**
116 * Create a transformation that allows us to serialize a DOM Node
117 * @param source
118 */
119 public Transform(Node sourceNode) {
120 this(sourceNode, (Source)null);
121 }
122
123 /**
124 * Create a transformation from an input Node and stylesheet in a String
125 * @param sourceNode
126 * @param stylesheet
127 */
128 public Transform(Node sourceNode, String stylesheet) {
129 this(sourceNode, new StreamSource(new StringReader(stylesheet)));
130 }
131
132 /**
133 * Create a transformation from an input Node and stylesheet in a File
134 * @param sourceNode
135 * @param stylesheet
136 */
137 public Transform(Node sourceNode, File stylesheet) {
138 this(sourceNode, new StreamSource(stylesheet));
139 }
140
141 /**
142 * Create a transformation from an input Node and stylesheet in a Source
143 * @param sourceNode
144 * @param stylesheetSource
145 */
146 private Transform(Node sourceNode, Source stylesheetSource) {
147 this(new DOMSource(sourceNode), stylesheetSource);
148 }
149
150 /**
151 * Create a transformation using Source input XML and Source stylesheet
152 * @param inputReader
153 * @param stylesheetReader
154 */
155 public Transform(Source inputSource, Source stylesheetSource) {
156 this.inputSource = inputSource;
157 provideSystemIdIfRequired(inputSource);
158
159 provideSystemIdIfRequired(stylesheetSource);
160 this.transformer = getTransformer(stylesheetSource);
161 }
162
163 /**
164 * Ensure that the source has a systemId
165 * @param source
166 */
167 private void provideSystemIdIfRequired(Source source) {
168 if (source!=null && (source.getSystemId() == null
169 || source.getSystemId().length() == 0)) {
170 source.setSystemId(getDefaultSystemId());
171 }
172 }
173
174 /**
175 * @return the current working directory as an URL-form string
176 */
177 private String getDefaultSystemId() {
178 try {
179 return PWD.toURL().toExternalForm();
180 } catch (MalformedURLException e) {
181 throw new XMLUnitRuntimeException("Unable to determine current "
182 + "working directory!", e);
183 }
184 }
185 /**
186 * Factory method
187 * @param stylesheetSource
188 * @throws ConfigurationException
189 * @return
190 */
191 private Transformer getTransformer(Source stylesheetSource)
192 throws ConfigurationException {
193 try {
194 TransformerFactory factory = XMLUnit.getTransformerFactory();
195 Transformer t = stylesheetSource == null
196 ? factory.newTransformer()
197 : factory.newTransformer(stylesheetSource);
198 return t;
199 } catch (javax.xml.transform.TransformerConfigurationException ex) {
200 throw new ConfigurationException(ex);
201 }
202 }
203
204 /**
205 * Perform the actual transformation
206 * @param result
207 * @throws TransformerException
208 */
209 protected void transformTo(Result result) throws TransformerException {
210 transformer.transform(inputSource, result);
211 }
212
213 /**
214 * Perform the XSLT transformation specified in the constructor
215 * @return the result as a String
216 * @throws TransformerException
217 */
218 public String getResultString() throws TransformerException {
219 StringWriter outputWriter = new StringWriter();
220 transformTo(new StreamResult(outputWriter));
221
222 return outputWriter.toString();
223 }
224
225 /**
226 * Perform the XSLT transformation specified in the constructor
227 * @return the result as a DOM Document
228 * @throws TransformerException
229 */
230 public Document getResultDocument() throws TransformerException {
231 DOMResult result = new DOMResult();
232 transformTo(result);
233
234 return (Document) result.getNode();
235 }
236
237 /**
238 * Override an output property specified in the transformation stylesheet
239 * @param name
240 * @param value
241 */
242 public void setOutputProperty(String name, String value) {
243 Properties properties = new Properties();
244 properties.setProperty(name, value);
245 setOutputProperties(properties);
246 }
247
248 /**
249 * Override output properties specified in the transformation stylesheet
250 * @param outputProperties
251 * @see Transformer#setOutputProperties(java.util.Properties)
252 */
253 public void setOutputProperties(Properties outputProperties) {
254 transformer.setOutputProperties(outputProperties);
255 }
256
257 /**
258 * Add a parameter for the transformation
259 * @param name
260 * @param value
261 * @see Transformer#setParameter(java.lang.String, java.lang.Object)
262 */
263 public void setParameter(String name, Object value) {
264 transformer.setParameter(name, value);
265 }
266
267 /**
268 * See a parameter used for the transformation
269 * @param name
270 * @return the parameter value
271 * @see Transformer#getParameter(java.lang.String)
272 */
273 public Object getParameter(String name) {
274 return transformer.getParameter(name);
275 }
276
277 /**
278 * Clear parameters used for the transformation
279 * @see Transformer#clearParameters()
280 */
281 public void clearParameters() {
282 transformer.clearParameters();
283 }
284
285 /**
286 * Set the URIResolver for the transformation
287 * @see Transformer#setURIResolver(javax.xml.transform.URIResolver)
288 */
289 public void setURIResolver(URIResolver uriResolver) {
290 transformer.setURIResolver(uriResolver);
291 }
292
293 /**
294 * Set the ErrorListener for the transformation
295 * @see Transformer#setErrorListener(javax.xml.transform.ErrorListener)
296 */
297 public void setErrorListener(ErrorListener errorListener) {
298 transformer.setErrorListener(errorListener);
299 }
300 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
40
41 import java.io.IOException;
42 import java.io.InputStreamReader;
43 import java.io.Reader;
44 import java.io.StringReader;
45
46 import org.w3c.dom.Document;
47 import org.xml.sax.ErrorHandler;
48 import org.xml.sax.InputSource;
49 import org.xml.sax.SAXException;
50 import org.xml.sax.SAXNotRecognizedException;
51 import org.xml.sax.SAXNotSupportedException;
52 import org.xml.sax.SAXParseException;
53 import org.xml.sax.helpers.DefaultHandler;
54
55 import javax.xml.parsers.ParserConfigurationException;
56 import javax.xml.parsers.SAXParser;
57 import javax.xml.parsers.SAXParserFactory;
58
59 /**
60 * Validates XML against its internal or external DOCTYPE, or a completely
61 * different DOCTYPE.
62 * Usage:
63 * <ul>
64 * <li><code>new Validator(readerForXML);</code> <br/>
65 * to validate some XML that contains or references an accessible DTD or
66 * schema
67 * </li>
68 * <li><code>new Validator(readerForXML, systemIdForValidation);</code> <br/>
69 * to validate some XML that references a DTD but using a local systemId
70 * to perform the validation
71 * </li>
72 * <li><code>new Validator(readerForXML, systemIdForValidation, doctypeName);</code> <br/>
73 * to validate some XML against a completely different DTD
74 * </li>
75 * </ul>
76 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
77 */
78 public class Validator extends DefaultHandler implements ErrorHandler {
79 private final InputSource validationInputSource;
80 private final SAXParser parser;
81 private final StringBuffer messages;
82 private final boolean usingDoctypeReader;
83
84 private Boolean isValid;
85
86 /**
87 * Kept for backwards compatibility.
88 * @deprecated Use the protected three arg constructor instead.
89 */
90 protected Validator(InputSource inputSource,
91 boolean usingDoctypeReader)
92 throws SAXException, ConfigurationException {
93 this(inputSource, null, usingDoctypeReader);
94 }
95
96 /**
97 * Baseline constructor: called by all others
98 *
99 * @param inputSource
100 * @param systemId
101 * @param usingDoctypeReader
102 * @throws SAXException
103 * @throws ConfigurationException if validation could not be turned on
104 */
105 protected Validator(InputSource inputSource,
106 String systemId,
107 boolean usingDoctypeReader)
108 throws SAXException, ConfigurationException {
109 isValid = null;
110 messages = new StringBuffer();
111 SAXParserFactory factory = XMLUnit.getSAXParserFactory();
112 factory.setValidating(true);
113 try {
114 parser = factory.newSAXParser();
115 } catch (ParserConfigurationException ex) {
116 throw new ConfigurationException(ex);
117 }
118
119 this.validationInputSource = inputSource;
120 if (systemId != null) {
121 validationInputSource.setSystemId(systemId);
122 }
123 this.usingDoctypeReader = usingDoctypeReader;
124 }
125
126 /**
127 * DOM-style constructor: allows Document validation post-manipulation
128 * of the DOM tree's contents.
129 * This takes a fairly tortuous route to validation as DOM level 2 does
130 * not allow creation of Doctype nodes.
131 * The supplied systemId and doctype name will replace any Doctype
132 * settings in the Document.
133 *
134 * @param document
135 * @param systemID
136 * @param doctype
137 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
138 * @throws ConfigurationException if validation could not be turned on
139 */
140 public Validator(Document document, String systemID, String doctype)
141 throws SAXException, ConfigurationException {
142 this(new InputStreamReader(new NodeInputStream(document)),
143 systemID, doctype);
144 }
145
146 /**
147 * Basic constructor.
148 * Validates the contents of the Reader using the DTD or schema referenced
149 * by those contents.
150 *
151 * @param readerForValidation
152 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
153 * @throws ConfigurationException if validation could not be turned on
154 */
155 public Validator(Reader readerForValidation)
156 throws SAXException, ConfigurationException {
157 this(readerForValidation, null);
158 }
159
160 /**
161 * Basic constructor.
162 * Validates the contents of the String using the DTD or schema referenced
163 * by those contents.
164 *
165 * @param stringForValidation
166 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
167 * @throws ConfigurationException if validation could not be turned on
168 */
169 public Validator(String stringForValidation)
170 throws SAXException, ConfigurationException {
171 this(new StringReader(stringForValidation));
172 }
173
174 /**
175 * Basic constructor.
176 * Validates the contents of the InputSource using the DTD or
177 * schema referenced by those contents.
178 *
179 * @param readerForValidation
180 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
181 * @throws ConfigurationException if validation could not be turned on
182 */
183 public Validator(InputSource sourceForValidation)
184 throws SAXException, ConfigurationException {
185 this(sourceForValidation, null);
186 }
187
188 /**
189 * Extended constructor.
190 * Validates the contents of the Reader using the DTD specified with the
191 * systemID. There must be DOCTYPE instruction in the markup that
192 * references the DTD or else the markup will be considered invalid: if
193 * there is no DOCTYPE in the markup use the 3-argument constructor
194 *
195 * @param readerForValidation
196 * @param systemID
197 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
198 * @throws ConfigurationException if validation could not be turned on
199 */
200 public Validator(Reader readerForValidation, String systemID)
201 throws SAXException, ConfigurationException {
202 this(new InputSource(readerForValidation), systemID,
203 (readerForValidation instanceof DoctypeReader));
204 }
205
206 /**
207 * Extended constructor.
208 * Validates the contents of the String using the DTD specified with the
209 * systemID. There must be DOCTYPE instruction in the markup that
210 * references the DTD or else the markup will be considered invalid: if
211 * there is no DOCTYPE in the markup use the 3-argument constructor
212 *
213 * @param stringForValidation
214 * @param systemID
215 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
216 * @throws ConfigurationException if validation could not be turned on
217 */
218 public Validator(String stringForValidation, String systemID)
219 throws SAXException, ConfigurationException {
220 this(new StringReader(stringForValidation), systemID);
221 }
222
223 /**
224 * Extended constructor.
225 * Validates the contents of the InputSource using the DTD
226 * specified with the systemID. There must be DOCTYPE instruction
227 * in the markup that references the DTD or else the markup will
228 * be considered invalid: if there is no DOCTYPE in the markup use
229 * the 3-argument constructor
230 *
231 * @param sourceForValidation
232 * @param systemID
233 * @throws SAXException if unable to obtain new Sax parser via JAXP factory
234 * @throws ConfigurationException if validation could not be turned on
235 */
236 public Validator(InputSource sourceForValidation, String systemID)
237 throws SAXException, ConfigurationException {
238 this(sourceForValidation, systemID, false);
239 }
240
241 /**
242 * Full constructor.
243 * Validates the contents of the InputSource using the DTD
244 * specified with the systemID and named with the doctype name.
245 *
246 * @param sourceForValidation
247 * @param systemID
248 * @param doctype
249 * @throws SAXException
250 * @throws ConfigurationException if validation could not be turned on
251 */
252 public Validator(InputSource sourceForValidation, String systemID,
253 String doctype)
254 throws SAXException, ConfigurationException {
255 this(sourceForValidation.getCharacterStream() != null
256 ? new InputSource(new DoctypeReader(sourceForValidation
257 .getCharacterStream(),
258 doctype, systemID))
259 : new InputSource(new DoctypeInputStream(sourceForValidation
260 .getByteStream(),
261 sourceForValidation
262 .getEncoding(),
263 doctype, systemID)),
264 systemID, true);
265 }
266
267 /**
268 * Full constructor.
269 * Validates the contents of the Reader using the DTD specified with the
270 * systemID and named with the doctype name.
271 *
272 * @param readerForValidation
273 * @param systemID
274 * @param doctype
275 * @throws SAXException
276 * @throws ConfigurationException if validation could not be turned on
277 */
278 public Validator(Reader readerForValidation, String systemID,
279 String doctype)
280 throws SAXException, ConfigurationException {
281 this(readerForValidation instanceof DoctypeReader
282 ? readerForValidation
283 : new DoctypeReader(readerForValidation, doctype, systemID),
284 systemID);
285 }
286
287 /**
288 * Turn on XML Schema validation.
289 *
290 * <p><b>This feature should work with any XML parser that is JAXP
291 * 1.2 compliant and supports XML Schema validation.</b></p>
292 *
293 * <p>For a fully JAXP 1.2 compliant parser the property {@link
294 * JAXPConstants.Properties.SCHEMA_LANGUAGE
295 * http://java.sun.com/xml/jaxp/properties/schemaLanguage} is set,
296 * if this fails the method falls back to the features
297 * http://apache.org/xml/features/validation/schema &amp;
298 * http://apache.org/xml/features/validation/dynamic which should
299 * cover early versions of Xerces 2 as well.</p>
300 *
301 * @param use indicate that XML Schema should be used to validate
302 * documents.
303 * @throws SAXException
304 * @see #setJAXP12SchemaSource(Object)
305 */
306 public void useXMLSchema(boolean use) throws SAXException {
307 boolean tryXercesProperties = false;
308 try {
309 if (use) {
310 parser.setProperty(JAXPConstants.Properties.SCHEMA_LANGUAGE,
311 XMLConstants.W3C_XML_SCHEMA_NS_URI);
312 }
313 } catch (SAXNotRecognizedException e) {
314 tryXercesProperties = true;
315 } catch (SAXNotSupportedException e) {
316 tryXercesProperties = true;
317 }
318
319 if (tryXercesProperties) {
320 parser.getXMLReader().setFeature("http://apache.org/xml/features/validation/schema", use);
321 parser.getXMLReader().setFeature("http://apache.org/xml/features/validation/dynamic", use);
322 }
323 }
324
325 /**
326 * Perform the validation of the source against DTD / Schema.
327 *
328 * @return true if the input supplied to the constructor passes validation,
329 * false otherwise
330 */
331 public boolean isValid() {
332 validate();
333 return isValid.booleanValue();
334 }
335
336 /**
337 * Assert that a document is valid.
338 */
339 public void assertIsValid(){
340 if(!isValid()){
341 junit.framework.Assert.fail(messages.toString());
342 }
343 }
344
345 /**
346 * Append any validation message(s) to the specified StringBuffer.
347 *
348 * @param toAppendTo
349 * @return specified StringBuffer with message(s) appended
350 */
351 private StringBuffer appendMessage(StringBuffer toAppendTo) {
352 if (isValid()) {
353 return toAppendTo.append("[valid]");
354 }
355 return toAppendTo.append(messages);
356 }
357
358 /**
359 * @return class name appended with validation messages
360 */
361 public String toString() {
362 StringBuffer buf = new StringBuffer(super.toString()).append(':');
363 return appendMessage(buf).toString();
364 }
365
366 /**
367 * Actually perform validation.
368 */
369 private void validate() {
370 if (isValid != null) {
371 return;
372 }
373
374 try {
375 parser.parse(validationInputSource, this);
376 } catch (SAXException e) {
377 parserException(e);
378 } catch (IOException e) {
379 parserException(e);
380 }
381
382 if (isValid == null) {
383 isValid = Boolean.TRUE;
384 } else if (usingDoctypeReader) {
385 try {
386 messages.append("\nContent was: ")
387 .append(getOriginalContent(validationInputSource));
388 } catch (IOException e) {
389 // silent but deadly?
390 }
391 }
392 }
393
394 /**
395 * Deal with any parser exceptions not handled by the ErrorHandler interface.
396 *
397 * @param e
398 */
399 private void parserException(Exception e) {
400 invalidate(e.getMessage());
401 }
402
403 /**
404 * ErrorHandler interface method.
405 *
406 * @param exception
407 * @throws SAXException
408 */
409 public void warning(SAXParseException exception)
410 throws SAXException {
411 errorHandlerException(exception);
412 }
413
414 /**
415 * ErrorHandler interface method.
416 *
417 * @param exception
418 * @throws SAXException
419 */
420 public void error(SAXParseException exception)
421 throws SAXException {
422 errorHandlerException(exception);
423 }
424
425 /**
426 * ErrorHandler interface method.
427 *
428 * @param exception
429 * @throws SAXException
430 */
431 public void fatalError(SAXParseException exception)
432 throws SAXException {
433 errorHandlerException(exception);
434 }
435
436 /**
437 * Entity Resolver method: allows us to override an existing systemID
438 * referenced in the markup DOCTYPE instruction.
439 *
440 * @param publicId
441 * @param systemId
442 * @return the sax InputSource that points to the overridden systemID
443 */
444 public InputSource resolveEntity(String publicId, String systemId) {
445 if (validationInputSource.getSystemId() != null) {
446 return new InputSource(validationInputSource.getSystemId());
447 } else {
448 InputSource s = null;
449 try {
450 if (XMLUnit.getControlEntityResolver() != null) {
451 s = XMLUnit.getControlEntityResolver()
452 .resolveEntity(publicId, systemId);
453 }
454 } catch (SAXException e) {
455 throw new XMLUnitRuntimeException("failed to resolve entity: "
456 + publicId, e);
457 } catch (IOException e) {
458 // even if we wanted to re-throw IOException (which we
459 // can't because of backwards compatibility) the mere
460 // fact that DefaultHandler has stripped IOException
461 // from EntityResolver's method's signature wouldn't
462 // let us.
463 throw new XMLUnitRuntimeException("failed to resolve entity: "
464 + publicId, e);
465 }
466 if (s != null) {
467 return s;
468 } else if (systemId != null) {
469 return new InputSource(systemId);
470 }
471 }
472 return null;
473 }
474
475 /**
476 * Deal with exceptions passed to the ErrorHandler interface by the parser.
477 */
478 private void errorHandlerException(SAXParseException e) {
479 String msg = "At line " + e.getLineNumber() + ", column: "
480 + e.getColumnNumber() + " ==> " + e.getMessage();
481 if (!msg.endsWith("\n")) msg += "\n";
482 invalidate(msg);
483 }
484
485 /**
486 * Set the validation status flag to false and capture the message for use
487 * later.
488 *
489 * @param message
490 */
491 private void invalidate(String message) {
492 isValid = Boolean.FALSE;
493 messages.append(message).append(' ');
494 }
495
496 /**
497 * As per JAXP 1.2 changes, which introduced a standard way for parsers to
498 * support schema validation. Since only W3C Schema support was included in
499 * JAXP 1.2, this is the only mechanism currently supported by this method.
500 *
501 * @param schemaSource
502 * This can be one of the following:
503 * <ul>
504 * <li>String that points to the URI of the schema</li>
505 * <li>InputStream with the contents of the schema</li>
506 * <li>SAX InputSource</li>
507 * <li>File</li>
508 * <li>an array of Objects with the contents being one of the
509 * types defined above. An array of Objects can be used only when
510 * the schema language has the ability to assemble a schema at
511 * runtime. When an array of Objects is passed it is illegal to
512 * have two schemas that share the same namespace.</li>
513 * </ul>
514 * @throws SAXException if this method of validating isn't supported.
515 * @see http://java.sun.com/webservices/jaxp/change-requests-11.html
516 */
517 public void setJAXP12SchemaSource(Object schemaSource) throws SAXException {
518 parser.setProperty(JAXPConstants.Properties.SCHEMA_SOURCE,
519 schemaSource);
520 }
521
522 private static String getOriginalContent(InputSource s)
523 throws IOException {
524 return s.getCharacterStream() instanceof DoctypeReader
525 ? ((DoctypeReader) s.getCharacterStream()).getContent()
526 : ((DoctypeInputStream) s.getByteStream())
527 .getContent(s.getEncoding());
528 }
529 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007,2011,2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XpathException;
40
41 import java.io.IOException;
42 import java.io.Reader;
43 import java.io.StringReader;
44 import java.util.Iterator;
45 import java.util.NoSuchElementException;
46
47 import javax.xml.parsers.DocumentBuilder;
48
49 import junit.framework.Assert;
50 import org.w3c.dom.Attr;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.Node;
54 import org.w3c.dom.NodeList;
55 import org.xml.sax.InputSource;
56 import org.xml.sax.SAXException;
57
58
59 /**
60 * Collection of static methods so that XML assertion facilities are available
61 * in any class, not just test suites. Thanks to Andrew McCormick and others for
62 * suggesting this refactoring.<br/>
63 * Available assertion methods are:
64 * <ul>
65 * <li><strong><code>assertXMLEqual</code></strong><br/>
66 * assert that two pieces of XML markup are <i>similar</i></li>
67 * <li><strong><code>assertXMLNotEqual</code></strong><br/>
68 * assert that two pieces of XML markup are <i>different</i></li>
69 * <li><strong><code>assertXMLIdentical</code></strong><br/>
70 * assert that two pieces of XML markup are <i>identical</i>. In most cases
71 * this assertion is too strong and <code>assertXMLEqual</code> is sufficient</li>
72 * <li><strong><code>assertXpathExists</code></strong><br/>
73 * assert that an XPath expression matches at least one node</li>
74 * <li><strong><code>assertXpathNotExists</code></strong><br/>
75 * assert that an XPath expression does not match any nodes</li>
76 * <li><strong><code>assertXpathsEqual</code></strong><br/>
77 * assert that the nodes obtained by executing two Xpaths
78 * are <i>similar</i></li>
79 * <li><strong><code>assertXpathsNotEqual</code></strong><br/>
80 * assert that the nodes obtained by executing two Xpaths
81 * are <i>different</i></li>
82 * <li><strong><code>assertXpathValuesEqual</code></strong><br/>
83 * assert that the flattened String obtained by executing two Xpaths
84 * are <i>similar</i></li>
85 * <li><strong><code>assertXpathValuesNotEqual</code></strong><br/>
86 * assert that the flattened String obtained by executing two Xpaths
87 * are <i>different</i></li>
88 * <li><strong><code>assertXpathEvaluatesTo</code></strong><br/>
89 * assert that the flattened String obtained by executing an Xpath
90 * is a particular value</li>
91 * <li><strong><code>assertXMLValid</code></strong><br/>
92 * assert that a piece of XML markup is valid with respect to a DTD: either
93 * by using the markup's own DTD or a different DTD</li>
94 * <li><strong><code>assertNodeTestPasses</code></strong><br/>
95 * assert that a piece of XML markup passes a {@link NodeTest NodeTest}</li>
96 * </ul>
97 * All underlying similarity and difference testing is done using
98 * {@link Diff Diff} instances which can be instantiated and evaluated
99 * independently of this class.
100 * @see Diff#similar()
101 * @see Diff#identical()
102 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
103 */
104 public class XMLAssert extends Assert implements XSLTConstants {
105
106 protected XMLAssert(){
107 super();
108 }
109
110 /**
111 * Assert that the result of an XML comparison is or is not similar.
112 * @param diff the result of an XML comparison
113 * @param assertion true if asserting that result is similar
114 */
115 public static void assertXMLEqual(Diff diff, boolean assertion) {
116 assertXMLEqual(null, diff, assertion);
117 }
118
119 /**
120 * Assert that the result of an XML comparison is or is not similar.
121 * @param msg additional message to display if assertion fails
122 * @param diff the result of an XML comparison
123 * @param assertion true if asserting that result is similar
124 */
125 public static void assertXMLEqual(String msg, Diff diff,
126 boolean assertion) {
127 if (assertion != diff.similar()) {
128 fail(getFailMessage(msg, diff));
129 }
130 }
131
132 private static String getFailMessage(String msg, Diff diff) {
133 StringBuffer sb = new StringBuffer();
134 if (msg != null && msg.length() > 0) {
135 sb.append(msg).append(", ");
136 }
137 return sb.append(diff.toString()).toString();
138 }
139
140 /**
141 * Assert that the result of an XML comparison is or is not identical
142 * @param diff the result of an XML comparison
143 * @param assertion true if asserting that result is identical
144 */
145 public static void assertXMLIdentical(Diff diff, boolean assertion) {
146 assertXMLIdentical(null, diff, assertion);
147 }
148
149 /**
150 * Assert that the result of an XML comparison is or is not identical
151 * @param msg Message to display if assertion fails
152 * @param diff the result of an XML comparison
153 * @param assertion true if asserting that result is identical
154 */
155 public static void assertXMLIdentical(String msg, Diff diff, boolean assertion) {
156 if (assertion != diff.identical()) {
157 fail(getFailMessage(msg, diff));
158 }
159 }
160
161 /**
162 * Assert that two XML documents are similar
163 * @param control XML to be compared against
164 * @param test XML to be tested
165 * @throws SAXException
166 * @throws IOException
167 */
168 public static void assertXMLEqual(InputSource control, InputSource test)
169 throws SAXException, IOException {
170 assertXMLEqual(null, control, test);
171 }
172
173 /**
174 * Assert that two XML documents are similar
175 * @param control XML to be compared against
176 * @param test XML to be tested
177 * @throws SAXException
178 * @throws IOException
179 */
180 public static void assertXMLEqual(String control, String test)
181 throws SAXException, IOException {
182 assertXMLEqual(null, control, test);
183 }
184
185 /**
186 * Assert that two XML documents are similar
187 * @param control XML to be compared against
188 * @param test XML to be tested
189 */
190 public static void assertXMLEqual(Document control, Document test) {
191 assertXMLEqual(null, control, test);
192 }
193
194 /**
195 * Assert that two XML documents are similar
196 * @param control XML to be compared against
197 * @param test XML to be tested
198 * @throws SAXException
199 * @throws IOException
200 */
201 public static void assertXMLEqual(Reader control, Reader test)
202 throws SAXException, IOException {
203 assertXMLEqual(null, control, test);
204 }
205
206 /**
207 * Assert that two XML documents are similar
208 * @param err Message to be displayed on assertion failure
209 * @param control XML to be compared against
210 * @param test XML to be tested
211 * @throws SAXException
212 * @throws IOException
213 */
214 public static void assertXMLEqual(String err, InputSource control,
215 InputSource test)
216 throws SAXException, IOException {
217 Diff diff = new Diff(control, test);
218 assertXMLEqual(err, diff, true);
219 }
220
221 /**
222 * Assert that two XML documents are similar
223 * @param err Message to be displayed on assertion failure
224 * @param control XML to be compared against
225 * @param test XML to be tested
226 * @throws SAXException
227 * @throws IOException
228 */
229 public static void assertXMLEqual(String err, String control, String test)
230 throws SAXException, IOException {
231 Diff diff = new Diff(control, test);
232 assertXMLEqual(err, diff, true);
233 }
234
235 /**
236 * Assert that two XML documents are similar
237 * @param err Message to be displayed on assertion failure
238 * @param control XML to be compared against
239 * @param test XML to be tested
240 */
241 public static void assertXMLEqual(String err, Document control,
242 Document test) {
243 Diff diff = new Diff(control, test);
244 assertXMLEqual(err, diff, true);
245 }
246
247 /**
248 * Assert that two XML documents are similar
249 * @param err Message to be displayed on assertion failure
250 * @param control XML to be compared against
251 * @param test XML to be tested
252 * @throws SAXException
253 * @throws IOException
254 */
255 public static void assertXMLEqual(String err, Reader control, Reader test)
256 throws SAXException, IOException {
257 Diff diff = new Diff(control, test);
258 assertXMLEqual(err, diff, true);
259 }
260
261 /**
262 * Assert that two XML documents are NOT similar
263 * @param control XML to be compared against
264 * @param test XML to be tested
265 * @throws SAXException
266 * @throws IOException
267 */
268 public static void assertXMLNotEqual(InputSource control, InputSource test)
269 throws SAXException, IOException {
270 assertXMLNotEqual(null, control, test);
271 }
272
273 /**
274 * Assert that two XML documents are NOT similar
275 * @param control XML to be compared against
276 * @param test XML to be tested
277 * @throws SAXException
278 * @throws IOException
279 */
280 public static void assertXMLNotEqual(String control, String test)
281 throws SAXException, IOException {
282 assertXMLNotEqual(null, control, test);
283 }
284
285 /**
286 * Assert that two XML documents are NOT similar
287 * @param control XML to be compared against
288 * @param test XML to be tested
289 */
290 public static void assertXMLNotEqual(Document control, Document test) {
291 assertXMLNotEqual(null, control, test);
292 }
293
294 /**
295 * Assert that two XML documents are NOT similar
296 * @param control XML to be compared against
297 * @param test XML to be tested
298 * @throws SAXException
299 * @throws IOException
300 */
301 public static void assertXMLNotEqual(Reader control, Reader test)
302 throws SAXException, IOException {
303 assertXMLNotEqual(null, control, test);
304 }
305
306 /**
307 * Assert that two XML documents are NOT similar
308 * @param err Message to be displayed on assertion failure
309 * @param control XML to be compared against
310 * @param test XML to be tested
311 * @throws SAXException
312 * @throws IOException
313 */
314 public static void assertXMLNotEqual(String err, InputSource control,
315 InputSource test)
316 throws SAXException, IOException {
317 Diff diff = new Diff(control, test);
318 assertXMLEqual(err, diff, false);
319 }
320
321 /**
322 * Assert that two XML documents are NOT similar
323 * @param err Message to be displayed on assertion failure
324 * @param control XML to be compared against
325 * @param test XML to be tested
326 * @throws SAXException
327 * @throws IOException
328 */
329 public static void assertXMLNotEqual(String err, String control, String test)
330 throws SAXException, IOException {
331 Diff diff = new Diff(control, test);
332 assertXMLEqual(err, diff, false);
333 }
334
335 /**
336 * Assert that two XML documents are NOT similar
337 * @param err Message to be displayed on assertion failure
338 * @param control XML to be compared against
339 * @param test XML to be tested
340 */
341 public static void assertXMLNotEqual(String err, Document control,
342 Document test) {
343 Diff diff = new Diff(control, test);
344 assertXMLEqual(err, diff, false);
345 }
346
347 /**
348 * Assert that two XML documents are NOT similar
349 * @param err Message to be displayed on assertion failure
350 * @param control XML to be compared against
351 * @param test XML to be tested
352 * @throws SAXException
353 * @throws IOException
354 */
355 public static void assertXMLNotEqual(String err, Reader control, Reader test)
356 throws SAXException, IOException {
357 Diff diff = new Diff(control, test);
358 assertXMLEqual(err, diff, false);
359 }
360
361 /**
362 * Assert that the node lists of two Xpaths in the same document are equal
363 * @param xpathOne
364 * @param xpathTwo
365 * @param document
366 * @see XpathEngine
367 */
368 public static void assertXpathsEqual(String controlXpath, String testXpath,
369 Document document)
370 throws XpathException {
371 assertXpathsEqual(controlXpath, document, testXpath, document);
372 }
373
374 /**
375 * Assert that the node lists of two Xpaths in the same document are equal
376 * @param xpathOne
377 * @param xpathTwo
378 * @param document
379 * @see XpathEngine
380 */
381 public static void assertXpathsEqual(String controlXpath, String testXpath,
382 InputSource document)
383 throws SAXException, IOException, XpathException {
384 assertXpathsEqual(controlXpath, testXpath,
385 XMLUnit.buildControlDocument(document));
386 }
387
388 /**
389 * Assert that the node lists of two Xpaths in the same XML string are
390 * equal
391 * @param xpathOne
392 * @param xpathTwo
393 * @param inXMLString
394 * @throws SAXException
395 * @throws IOException
396 */
397 public static void assertXpathsEqual(String controlXpath, String testXpath,
398 String inXMLString)
399 throws SAXException, IOException, XpathException {
400 assertXpathsEqual(controlXpath, testXpath,
401 XMLUnit.buildControlDocument(inXMLString));
402 }
403
404 /**
405 * Assert that the node lists of two Xpaths in two documents are equal
406 * @param xpathOne
407 * @param xpathTwo
408 * @param controlDocument
409 * @param testDocument
410 * @see XpathEngine
411 */
412 public static void assertXpathsEqual(String controlXpath,
413 InputSource controlDocument,
414 String testXpath,
415 InputSource testDocument)
416 throws SAXException, IOException, XpathException {
417 assertXpathsEqual(controlXpath,
418 XMLUnit.buildControlDocument(controlDocument),
419 testXpath,
420 XMLUnit.buildTestDocument(testDocument));
421 }
422
423 /**
424 * Assert that the node lists of two Xpaths in two XML strings are equal
425 * @param xpathOne
426 * @param inControlXMLString
427 * @param xpathTwo
428 * @param inTestXMLString
429 * @throws SAXException
430 * @throws IOException
431 */
432 public static void assertXpathsEqual(String controlXpath,
433 String inControlXMLString,
434 String testXpath,
435 String inTestXMLString)
436 throws SAXException, IOException,
437 XpathException {
438 assertXpathsEqual(
439 controlXpath, XMLUnit.buildControlDocument(inControlXMLString),
440 testXpath, XMLUnit.buildTestDocument(inTestXMLString));
441 }
442
443 /**
444 * Assert that the node lists of two Xpaths in two documents are equal
445 * @param xpathOne
446 * @param xpathTwo
447 * @param controlDocument
448 * @param testDocument
449 * @see XpathEngine
450 */
451 public static void assertXpathsEqual(String controlXpath,
452 Document controlDocument,
453 String testXpath,
454 Document testDocument)
455 throws XpathException {
456 assertXpathEquality(controlXpath, controlDocument, testXpath,
457 testDocument, true);
458 }
459
460 /**
461 * Assert that the node lists of two Xpaths in the same document are NOT equal
462 * @param xpathOne
463 * @param xpathTwo
464 * @param document
465 * @see XpathEngine
466 */
467 public static void assertXpathsNotEqual(String controlXpath,
468 String testXpath,
469 Document document)
470 throws XpathException {
471 assertXpathsNotEqual(controlXpath, document, testXpath, document);
472 }
473
474 /**
475 * Assert that the node lists of two Xpaths in the same document are NOT equal
476 * @param xpathOne
477 * @param xpathTwo
478 * @param document
479 * @see XpathEngine
480 */
481 public static void assertXpathsNotEqual(String controlXpath,
482 String testXpath,
483 InputSource document)
484 throws SAXException, IOException, XpathException {
485 assertXpathsNotEqual(controlXpath, testXpath,
486 XMLUnit.buildControlDocument(document));
487 }
488
489 /**
490 * Assert that the node lists of two Xpaths in the same XML string are NOT
491 * equal
492 * @param xpathOne
493 * @param xpathTwo
494 * @param inXMLString
495 * @throws SAXException
496 * @throws IOException
497 */
498 public static void assertXpathsNotEqual(String controlXpath,
499 String testXpath,
500 String inXMLString)
501 throws SAXException, IOException, XpathException {
502 assertXpathsNotEqual(controlXpath, testXpath,
503 XMLUnit.buildControlDocument(inXMLString));
504 }
505
506 /**
507 * Assert that the node lists of two Xpaths in two XML strings are NOT equal
508 * @param xpathOne
509 * @param inControlXMLString
510 * @param xpathTwo
511 * @param inTestXMLString
512 * @throws SAXException
513 * @throws IOException
514 */
515 public static void assertXpathsNotEqual(String controlXpath,
516 String inControlXMLString,
517 String testXpath,
518 String inTestXMLString)
519 throws SAXException, IOException,
520 XpathException {
521 assertXpathsNotEqual(
522 controlXpath, XMLUnit.buildControlDocument(inControlXMLString),
523 testXpath, XMLUnit.buildTestDocument(inTestXMLString));
524 }
525
526 /**
527 * Assert that the node lists of two Xpaths in two XML strings are
528 * NOT equal
529 * @param xpathOne
530 * @param controlDocument
531 * @param xpathTwo
532 * @param testDocument
533 * @throws SAXException
534 * @throws IOException
535 */
536 public static void assertXpathsNotEqual(String controlXpath,
537 InputSource controlDocument,
538 String testXpath,
539 InputSource testDocument)
540 throws SAXException, IOException, XpathException {
541 assertXpathsNotEqual(controlXpath,
542 XMLUnit.buildControlDocument(controlDocument),
543 testXpath,
544 XMLUnit.buildTestDocument(testDocument));
545 }
546
547 /**
548 * Assert that the node lists of two Xpaths in two documents are NOT equal
549 * @param xpathOne
550 * @param xpathTwo
551 * @param document
552 * @see XpathEngine
553 */
554 public static void assertXpathsNotEqual(String controlXpath,
555 Document controlDocument,
556 String testXpath,
557 Document testDocument)
558 throws XpathException {
559 assertXpathEquality(controlXpath, controlDocument, testXpath,
560 testDocument, false);
561 }
562
563 /**
564 * Assert that the node lists of two Xpaths in two documents are
565 * equal or not.
566 * @param xpathOne
567 * @param xpathTwo
568 * @param document
569 * @param equality whether the values should be equal.
570 * @see XpathEngine
571 */
572 private static void assertXpathEquality(String controlXpath,
573 Document controlDocument,
574 String testXpath,
575 Document testDocument,
576 boolean equal)
577 throws XpathException {
578 XpathEngine xpath = XMLUnit.newXpathEngine();
579 Diff diff = new Diff(asXpathResultDocument(XMLUnit.newControlParser(),
580 xpath.getMatchingNodes(controlXpath,
581 controlDocument)),
582 asXpathResultDocument(XMLUnit.newTestParser(),
583 xpath.getMatchingNodes(testXpath,
584 testDocument)));
585 assertXMLEqual(diff, equal);
586 }
587
588 /**
589 * Assert that the evaluation of two Xpaths in the same document are equal
590 * @param xpathOne
591 * @param xpathTwo
592 * @param document
593 * @see XpathEngine
594 */
595 public static void assertXpathValuesEqual(String controlXpath,
596 String testXpath,
597 Document document)
598 throws XpathException {
599 assertXpathValuesEqual(controlXpath, document, testXpath, document);
600 }
601
602 /**
603 * Assert that the evaluation of two Xpaths in the same XML string are
604 * equal
605 * @param xpathOne
606 * @param xpathTwo
607 * @param document
608 * @throws SAXException
609 * @throws IOException
610 */
611 public static void assertXpathValuesEqual(String controlXpath,
612 String testXpath,
613 InputSource document)
614 throws SAXException, IOException, XpathException {
615 assertXpathValuesEqual(controlXpath, testXpath,
616 XMLUnit.buildControlDocument(document));
617 }
618
619 /**
620 * Assert that the evaluation of two Xpaths in the same XML string are
621 * equal
622 * @param xpathOne
623 * @param xpathTwo
624 * @param inXMLString
625 * @throws SAXException
626 * @throws IOException
627 */
628 public static void assertXpathValuesEqual(String controlXpath,
629 String testXpath,
630 String inXMLString)
631 throws SAXException, IOException,
632 XpathException {
633 assertXpathValuesEqual(controlXpath, testXpath,
634 XMLUnit.buildControlDocument(inXMLString));
635 }
636
637 /**
638 * Assert that the evaluation of two Xpaths in two XML strings are equal
639 * @param xpathOne
640 * @param control
641 * @param xpathTwo
642 * @param test
643 * @throws SAXException
644 * @throws IOException
645 */
646 public static void assertXpathValuesEqual(String controlXpath,
647 InputSource control,
648 String testXpath,
649 InputSource test)
650 throws SAXException, IOException, XpathException {
651 assertXpathValuesEqual(controlXpath,
652 XMLUnit.buildControlDocument(control),
653 testXpath,
654 XMLUnit.buildTestDocument(test));
655 }
656
657 /**
658 * Assert that the evaluation of two Xpaths in two XML strings are equal
659 * @param xpathOne
660 * @param inControlXMLString
661 * @param xpathTwo
662 * @param inTestXMLString
663 * @throws SAXException
664 * @throws IOException
665 */
666 public static void assertXpathValuesEqual(String controlXpath,
667 String inControlXMLString,
668 String testXpath,
669 String inTestXMLString)
670 throws SAXException, IOException,
671 XpathException {
672 assertXpathValuesEqual(controlXpath,
673 XMLUnit.buildControlDocument(inControlXMLString),
674 testXpath,
675 XMLUnit.buildTestDocument(inTestXMLString));
676 }
677
678 /**
679 * Assert that the evaluation of two Xpaths in two documents are equal
680 * @param xpathOne
681 * @param xpathTwo
682 * @param document
683 * @see XpathEngine
684 */
685 public static void assertXpathValuesEqual(String controlXpath,
686 Document controlDocument,
687 String testXpath,
688 Document testDocument)
689 throws XpathException {
690 XpathEngine xpath = XMLUnit.newXpathEngine();
691 assertEquals(xpath.evaluate(controlXpath, controlDocument),
692 xpath.evaluate(testXpath, testDocument));
693 }
694
695 /**
696 * Assert that the evaluation of two Xpaths in the same XML string are
697 * NOT equal
698 * @param xpathOne
699 * @param xpathTwo
700 * @param control
701 * @throws SAXException
702 * @throws IOException
703 */
704 public static void assertXpathValuesNotEqual(String controlXpath,
705 String testXpath,
706 InputSource control)
707 throws SAXException, IOException, XpathException {
708 assertXpathValuesNotEqual(controlXpath, testXpath,
709 XMLUnit.buildControlDocument(control));
710 }
711
712 /**
713 * Assert that the evaluation of two Xpaths in the same XML string are
714 * NOT equal
715 * @param xpathOne
716 * @param xpathTwo
717 * @param inXMLString
718 * @throws SAXException
719 * @throws IOException
720 */
721 public static void assertXpathValuesNotEqual(String controlXpath,
722 String testXpath,
723 String inXMLString)
724 throws SAXException, IOException,
725 XpathException {
726 assertXpathValuesNotEqual(controlXpath, testXpath,
727 XMLUnit.buildControlDocument(inXMLString));
728 }
729
730 /**
731 * Assert that the evaluation of two Xpaths in the same document are
732 * NOT equal
733 * @param xpathOne
734 * @param xpathTwo
735 * @param document
736 */
737 public static void assertXpathValuesNotEqual(String controlXpath,
738 String testXpath,
739 Document document)
740 throws XpathException {
741 assertXpathValuesNotEqual(controlXpath, document, testXpath, document);
742 }
743
744 /**
745 * Assert that the evaluation of two Xpaths in two XML strings are
746 * NOT equal
747 * @param xpathOne
748 * @param control
749 * @param xpathTwo
750 * @param test
751 * @throws SAXException
752 * @throws IOException
753 */
754 public static void assertXpathValuesNotEqual(String controlXpath,
755 InputSource control,
756 String testXpath,
757 InputSource test)
758 throws SAXException, IOException, XpathException {
759 assertXpathValuesNotEqual(controlXpath,
760 XMLUnit.buildControlDocument(control),
761 testXpath,
762 XMLUnit.buildTestDocument(test));
763 }
764
765 /**
766 * Assert that the evaluation of two Xpaths in two XML strings are
767 * NOT equal
768 * @param xpathOne
769 * @param inControlXMLString
770 * @param xpathTwo
771 * @param inTestXMLString
772 * @throws SAXException
773 * @throws IOException
774 */
775 public static void assertXpathValuesNotEqual(String controlXpath,
776 String inControlXMLString,
777 String testXpath,
778 String inTestXMLString)
779 throws SAXException, IOException,
780 XpathException {
781 assertXpathValuesNotEqual(controlXpath,
782 XMLUnit.buildControlDocument(inControlXMLString),
783 testXpath,
784 XMLUnit.buildTestDocument(inTestXMLString));
785 }
786
787 /**
788 * Assert that the evaluation of two Xpaths in two documents are
789 * NOT equal
790 * @param xpathOne
791 * @param xpathTwo
792 * @param document
793 */
794 public static void assertXpathValuesNotEqual(String controlXpath,
795 Document controlDocument,
796 String testXpath,
797 Document testDocument)
798 throws XpathException {
799 XpathEngine xpath = XMLUnit.newXpathEngine();
800 String control = xpath.evaluate(controlXpath, controlDocument);
801 String test = xpath.evaluate(testXpath, testDocument);
802 if (control!=null) {
803 if (control.equals(test)) {
804 fail("Expected test value NOT to be equal to control but both were "
805 + test);
806 }
807 } else if (test != null) {
808 fail("control xPath evaluated to empty node set, "
809 + "but test xPath evaluated to " + test);
810 }
811 }
812
813 /**
814 * Assert the value of an Xpath expression in an XML document.
815 * @param expectedValue
816 * @param xpathExpression
817 * @param control
818 * @throws SAXException
819 * @throws IOException
820 * @see XpathEngine which provides the underlying evaluation mechanism
821 */
822 public static void assertXpathEvaluatesTo(String expectedValue,
823 String xpathExpression,
824 InputSource control)
825 throws SAXException, IOException,
826 XpathException {
827 Document document = XMLUnit.buildControlDocument(control);
828 assertXpathEvaluatesTo(expectedValue, xpathExpression, document);
829 }
830
831 /**
832 * Assert the value of an Xpath expression in an XML String
833 * @param expectedValue
834 * @param xpathExpression
835 * @param inXMLString
836 * @throws SAXException
837 * @throws IOException
838 * @see XpathEngine which provides the underlying evaluation mechanism
839 */
840 public static void assertXpathEvaluatesTo(String expectedValue,
841 String xpathExpression,
842 String inXMLString)
843 throws SAXException, IOException,
844 XpathException {
845 Document document = XMLUnit.buildControlDocument(inXMLString);
846 assertXpathEvaluatesTo(expectedValue, xpathExpression, document);
847 }
848
849 /**
850 * Assert the value of an Xpath expression in an DOM Document
851 * @param expectedValue
852 * @param xpathExpression
853 * @param inDocument
854 * @see XpathEngine which provides the underlying evaluation mechanism
855 */
856 public static void assertXpathEvaluatesTo(String expectedValue,
857 String xpathExpression,
858 Document inDocument)
859 throws XpathException {
860 XpathEngine simpleXpathEngine = XMLUnit.newXpathEngine();
861 assertEquals(expectedValue,
862 simpleXpathEngine.evaluate(xpathExpression, inDocument));
863 }
864
865 /**
866 * Assert the value of an Xpath expression in an XML document.
867 * @param expectedValue
868 * @param xpathExpression
869 * @param control
870 * @throws SAXException
871 * @throws IOException
872 * @see XpathEngine which provides the underlying evaluation mechanism
873 */
874 public static void assertXpathEvaluatesTo(QualifiedName expectedValue,
875 String xpathExpression,
876 InputSource control)
877 throws SAXException, IOException,
878 XpathException {
879 Document document = XMLUnit.buildControlDocument(control);
880 assertXpathEvaluatesTo(expectedValue, xpathExpression, document);
881 }
882
883 /**
884 * Assert the value of an Xpath expression in an XML String
885 * @param expectedValue
886 * @param xpathExpression
887 * @param inXMLString
888 * @throws SAXException
889 * @throws IOException
890 * @see XpathEngine which provides the underlying evaluation mechanism
891 */
892 public static void assertXpathEvaluatesTo(QualifiedName expectedValue,
893 String xpathExpression,
894 String inXMLString)
895 throws SAXException, IOException,
896 XpathException {
897 Document document = XMLUnit.buildControlDocument(inXMLString);
898 assertXpathEvaluatesTo(expectedValue, xpathExpression, document);
899 }
900
901 /**
902 * Assert the value of an Xpath expression in an DOM Document
903 * @param expectedValue
904 * @param xpathExpression
905 * @param inDocument
906 * @see XpathEngine which provides the underlying evaluation mechanism
907 */
908 public static void assertXpathEvaluatesTo(QualifiedName expectedValue,
909 String xpathExpression,
910 Document inDocument)
911 throws XpathException {
912 XpathEngine simpleXpathEngine = XMLUnit.newXpathEngine();
913 NodeList nl =
914 simpleXpathEngine.getMatchingNodes(xpathExpression, inDocument);
915 NamespaceContext ctx = null;
916 if (nl.getLength() > 0) {
917 ctx = new NodeBasedNamespaceContext(nl.item(0));
918 }
919 assertEquals(expectedValue,
920 QualifiedName
921 .valueOf(simpleXpathEngine.evaluate(xpathExpression,
922 inDocument),
923 ctx));
924 }
925
926 /**
927 * Assert that a specific XPath exists in some given XML
928 * @param inXpathExpression
929 * @param control
930 * @see XpathEngine which provides the underlying evaluation mechanism
931 */
932 public static void assertXpathExists(String xPathExpression,
933 InputSource control)
934 throws IOException, SAXException, XpathException {
935 Document inDocument = XMLUnit.buildControlDocument(control);
936 assertXpathExists(xPathExpression, inDocument);
937 }
938
939 /**
940 * Assert that a specific XPath exists in some given XML
941 * @param inXpathExpression
942 * @param inXMLString
943 * @see XpathEngine which provides the underlying evaluation mechanism
944 */
945 public static void assertXpathExists(String xPathExpression,
946 String inXMLString)
947 throws IOException, SAXException, XpathException {
948 Document inDocument = XMLUnit.buildControlDocument(inXMLString);
949 assertXpathExists(xPathExpression, inDocument);
950 }
951
952 /**
953 * Assert that a specific XPath exists in some given XML
954 * @param inXpathExpression
955 * @param inDocument
956 * @see XpathEngine which provides the underlying evaluation mechanism
957 */
958 public static void assertXpathExists(String xPathExpression,
959 Document inDocument)
960 throws XpathException {
961 XpathEngine simpleXpathEngine = XMLUnit.newXpathEngine();
962 NodeList nodeList = simpleXpathEngine.getMatchingNodes(
963 xPathExpression, inDocument);
964 int matches = nodeList.getLength();
965 assertTrue("Expecting to find matches for Xpath " +
966 xPathExpression, matches > 0);
967 }
968
969 /**
970 * Assert that a specific XPath does NOT exist in some given XML
971 * @param inXpathExpression
972 * @param control
973 * @see XpathEngine which provides the underlying evaluation mechanism
974 */
975 public static void assertXpathNotExists(String xPathExpression,
976 InputSource control)
977 throws IOException, SAXException, XpathException {
978 Document inDocument = XMLUnit.buildControlDocument(control);
979 assertXpathNotExists(xPathExpression, inDocument);
980 }
981
982 /**
983 * Assert that a specific XPath does NOT exist in some given XML
984 * @param inXpathExpression
985 * @param inXMLString
986 * @see XpathEngine which provides the underlying evaluation mechanism
987 */
988 public static void assertXpathNotExists(String xPathExpression,
989 String inXMLString)
990 throws IOException, SAXException, XpathException {
991 Document inDocument = XMLUnit.buildControlDocument(inXMLString);
992 assertXpathNotExists(xPathExpression, inDocument);
993 }
994
995 /**
996 * Assert that a specific XPath does NOT exist in some given XML
997 * @param inXpathExpression
998 * @param inDocument
999 * @see XpathEngine which provides the underlying evaluation mechanism
1000 */
1001 public static void assertXpathNotExists(String xPathExpression,
1002 Document inDocument)
1003 throws XpathException {
1004 XpathEngine simpleXpathEngine = XMLUnit.newXpathEngine();
1005 NodeList nodeList = simpleXpathEngine.getMatchingNodes(
1006 xPathExpression, inDocument);
1007 int matches = nodeList.getLength();
1008 assertEquals("Should be zero matches for Xpath " +
1009 xPathExpression, 0, matches);
1010 }
1011
1012 /**
1013 * Assert that an InputSource containing XML contains valid XML:
1014 * the document must contain a DOCTYPE declaration to be validated
1015 * @param xml
1016 * @throws SAXException
1017 * @throws ConfigurationException if validation could not be turned on
1018 * @see Validator
1019 */
1020 public static void assertXMLValid(InputSource xml)
1021 throws SAXException, ConfigurationException {
1022 assertXMLValid(new Validator(xml));
1023 }
1024
1025 /**
1026 * Assert that a String containing XML contains valid XML: the String must
1027 * contain a DOCTYPE declaration to be validated
1028 * @param xmlString
1029 * @throws SAXException
1030 * @throws ConfigurationException if validation could not be turned on
1031 * @see Validator
1032 */
1033 public static void assertXMLValid(String xmlString)
1034 throws SAXException, ConfigurationException {
1035 assertXMLValid(new Validator(xmlString));
1036 }
1037
1038 /**
1039 * Assert that an InputSource containing XML contains valid XML:
1040 * the document must contain a DOCTYPE to be validated, but the
1041 * validation will use the systemId to obtain the DTD
1042 * @param xml
1043 * @param systemId
1044 * @throws SAXException
1045 * @throws ConfigurationException if validation could not be turned on
1046 * @see Validator
1047 */
1048 public static void assertXMLValid(InputSource xml, String systemId)
1049 throws SAXException, ConfigurationException {
1050 assertXMLValid(new Validator(xml, systemId));
1051 }
1052
1053 /**
1054 * Assert that a String containing XML contains valid XML: the String must
1055 * contain a DOCTYPE to be validated, but the validation will use the
1056 * systemId to obtain the DTD
1057 * @param xmlString
1058 * @param systemId
1059 * @throws SAXException
1060 * @throws ConfigurationException if validation could not be turned on
1061 * @see Validator
1062 */
1063 public static void assertXMLValid(String xmlString, String systemId)
1064 throws SAXException, ConfigurationException {
1065 assertXMLValid(new Validator(xmlString, systemId));
1066 }
1067
1068 /**
1069 * Assert that a piece of XML contains valid XML: the document
1070 * will be given a DOCTYPE to be validated with the name and
1071 * systemId specified regardless of whether it already contains a
1072 * doctype declaration.
1073 * @param xml
1074 * @param systemId
1075 * @param doctype
1076 * @throws SAXException
1077 * @throws ConfigurationException if validation could not be turned on
1078 * @see Validator
1079 */
1080 public static void assertXMLValid(InputSource xml, String systemId,
1081 String doctype)
1082 throws SAXException, ConfigurationException {
1083 assertXMLValid(new Validator(xml, systemId, doctype));
1084 }
1085
1086 /**
1087 * Assert that a String containing XML contains valid XML: the String will
1088 * be given a DOCTYPE to be validated with the name and systemId specified
1089 * regardless of whether it already contains a doctype declaration.
1090 * @param xmlString
1091 * @param systemId
1092 * @param doctype
1093 * @throws SAXException
1094 * @throws ConfigurationException if validation could not be turned on
1095 * @see Validator
1096 */
1097 public static void assertXMLValid(String xmlString, String systemId, String doctype)
1098 throws SAXException, ConfigurationException {
1099 assertXMLValid(new Validator(new StringReader(xmlString), systemId, doctype));
1100 }
1101
1102 /**
1103 * Assert that a Validator instance returns <code>isValid() == true</code>
1104 * @param validator
1105 */
1106 public static void assertXMLValid(Validator validator) {
1107 assertEquals(validator.toString(), true, validator.isValid());
1108 }
1109
1110 /**
1111 * Execute a <code>NodeTest<code> for a single node type
1112 * and assert that it passes
1113 * @param xml XML to be tested
1114 * @param tester The test strategy
1115 * @param nodeType The node type to be tested: constants defined
1116 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
1117 * @throws SAXException
1118 * @throws IOException
1119 * @see AbstractNodeTester
1120 * @see CountingNodeTester
1121 */
1122 public static void assertNodeTestPasses(InputSource xml, NodeTester tester,
1123 short nodeType)
1124 throws SAXException, IOException {
1125 NodeTest test = new NodeTest(xml);
1126 assertNodeTestPasses(test, tester, new short[] {nodeType}, true);
1127 }
1128
1129 /**
1130 * Execute a <code>NodeTest<code> for a single node type
1131 * and assert that it passes
1132 * @param xmlString XML to be tested
1133 * @param tester The test strategy
1134 * @param nodeType The node type to be tested: constants defined
1135 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
1136 * @throws SAXException
1137 * @throws IOException
1138 * @see AbstractNodeTester
1139 * @see CountingNodeTester
1140 */
1141 public static void assertNodeTestPasses(String xmlString, NodeTester tester,
1142 short nodeType)
1143 throws SAXException, IOException {
1144 NodeTest test = new NodeTest(xmlString);
1145 assertNodeTestPasses(test, tester, new short[] {nodeType}, true);
1146 }
1147
1148 /**
1149 * Execute a <code>NodeTest<code> for multiple node types and make an
1150 * assertion about it whether it is expected to pass
1151 * @param test a NodeTest instance containing the XML source to be tested
1152 * @param tester The test strategy
1153 * @param nodeTypes The node types to be tested: constants defined
1154 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
1155 * @param assertion true if the test is expected to pass, false otherwise
1156 * @see AbstractNodeTester
1157 * @see CountingNodeTester
1158 */
1159 public static void assertNodeTestPasses(NodeTest test, NodeTester tester,
1160 short[] nodeTypes, boolean assertion) {
1161 try {
1162 test.performTest(tester, nodeTypes);
1163 if (!assertion) {
1164 fail("Expected node test to fail, but it passed!");
1165 }
1166 } catch (NodeTestException e) {
1167 if (assertion) {
1168 fail("Expected node test to pass, but it failed! "
1169 + e.getMessage());
1170 }
1171 }
1172 }
1173
1174 private static Document asXpathResultDocument(final DocumentBuilder builder,
1175 final NodeList nodes) {
1176 final Document d = builder.newDocument();
1177 final Element root = d.createElement("xpathResult");
1178 d.appendChild(root);
1179 final int length = nodes.getLength();
1180 for (int i = 0; i < length; i++) {
1181 Node n = d.importNode(nodes.item(i), true);
1182 if (n instanceof Attr) {
1183 root.setAttributeNodeNS((Attr) n);
1184 } else {
1185 root.appendChild(n);
1186 }
1187 }
1188 return d;
1189 }
1190
1191 private static class NodeBasedNamespaceContext implements NamespaceContext {
1192 private final Node node;
1193 NodeBasedNamespaceContext(Node n) {
1194 node = n;
1195 }
1196 public String getNamespaceURI(String prefix) {
1197 return node.lookupNamespaceURI(prefix);
1198 }
1199
1200 // not used in context of #assertXpathEvaluatesTo
1201 public Iterator getPrefixes() {
1202 return new Iterator() {
1203 public boolean hasNext() {
1204 return false;
1205 }
1206 public Object next() {
1207 throw new NoSuchElementException();
1208 }
1209 public void remove() {
1210 throw new UnsupportedOperationException();
1211 }
1212 };
1213 }
1214 }
1215 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * A convenient place to hang constants relating to general XML usage
40 */
41 public interface XMLConstants {
42
43 /**
44 * &lt;?xml&gt; declaration
45 */
46 public static final String XML_DECLARATION =
47 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
48
49 /**
50 * xmlns attribute prefix
51 */
52 public static final String XMLNS_PREFIX = "xmlns";
53
54 /**
55 * xmlns URI
56 */
57 public static final String XMLNS_ATTRIBUTE_URI = "http://www.w3.org/2000/xmlns/";
58
59 /**
60 * "&lt;"
61 */
62 public static final String OPEN_START_NODE = "<";
63
64 /**
65 * "&lt;/"
66 */
67 public static final String OPEN_END_NODE = "</";
68
69 /**
70 * "&gt;"
71 */
72 public static final String CLOSE_NODE = ">";
73
74 /**
75 * "![CDATA["
76 */
77 public static final String START_CDATA = "![CDATA[";
78 /**
79 * "]]"
80 */
81 public static final String END_CDATA = "]]";
82
83 /**
84 * "!--"
85 */
86 public static final String START_COMMENT = "!--";
87 /**
88 * "--""
89 */
90 public static final String END_COMMENT = "--";
91
92 /**
93 * "?"
94 */
95 public static final String START_PROCESSING_INSTRUCTION = "?";
96 /**
97 * "?"
98 */
99 public static final String END_PROCESSING_INSTRUCTION = "?";
100
101 /**
102 * "!DOCTYPE"
103 */
104 public static final String START_DOCTYPE = "!DOCTYPE ";
105
106 /**
107 * "/"
108 */
109 public static final String XPATH_SEPARATOR = "/";
110
111 /**
112 * "["
113 */
114 public static final String XPATH_NODE_INDEX_START = "[";
115
116 /**
117 * "]"
118 */
119 public static final String XPATH_NODE_INDEX_END = "]";
120
121 /**
122 * "comment()"
123 */
124 public static final String XPATH_COMMENT_IDENTIFIER = "comment()";
125
126 /**
127 * "processing-instruction()"
128 */
129 public static final String XPATH_PROCESSING_INSTRUCTION_IDENTIFIER = "processing-instruction()";
130
131 /**
132 * "text()"
133 */
134 public static final String XPATH_CHARACTER_NODE_IDENTIFIER = "text()";
135
136 /**
137 * "&at;"
138 */
139 public static final String XPATH_ATTRIBUTE_IDENTIFIER = "@";
140
141 /**
142 * http://www.w3.org/2001/XMLSchema
143 */
144 public static final String W3C_XML_SCHEMA_NS_URI
145 = "http://www.w3.org/2001/XMLSchema";
146
147 /**
148 * http://www.w3.org/2001/XMLSchema-instance
149 */
150 public static final String W3C_XML_SCHEMA_INSTANCE_NS_URI
151 = "http://www.w3.org/2001/XMLSchema-instance";
152
153 /**
154 * "schemaLocation"
155 */
156 public static final String W3C_XML_SCHEMA_INSTANCE_SCHEMA_LOCATION_ATTR
157 = "schemaLocation";
158
159 /**
160 * "noNamespaceSchemaLocation"
161 */
162 String W3C_XML_SCHEMA_INSTANCE_NO_NAMESPACE_SCHEMA_LOCATION_ATTR
163 = "noNamespaceSchemaLocation";
164
165 /**
166 * "type"
167 */
168 public static final String W3C_XML_SCHEMA_INSTANCE_TYPE_ATTR
169 = "type";
170
171 /**
172 * ""
173 */
174 String NULL_NS_URI = "";
175 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XpathException;
40
41 import java.io.IOException;
42 import java.io.Reader;
43 import java.io.StringReader;
44
45 import junit.framework.TestCase;
46 import org.w3c.dom.Document;
47 import org.xml.sax.InputSource;
48 import org.xml.sax.SAXException;
49
50
51 /**
52 * JUnit TestCase subclass: extend this to add XML assertion facilities to your
53 * test suites.
54 * Available assertions are provided by static methods of the {@link XMLAssert
55 * XMLAssert} class.
56 * NB: All underlying similarity and difference testing is done using {@link
57 * Diff Diff} instances which can be instantiated and evaluated independently of
58 * an XMLTestCase.
59 * @see Diff#similar()
60 * @see Diff#identical()
61 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
62 */
63 public abstract class XMLTestCase extends TestCase implements XSLTConstants {
64 /**
65 * Construct a new XML test case.
66 */
67 public XMLTestCase(){
68 super();
69 }
70
71 /**
72 * Construct a new test case.
73 * @param name Name of test
74 */
75 public XMLTestCase(String name){
76 super(name);
77 }
78
79 /**
80 * Compare XML documents provided by two InputSource classes
81 * @param control Control document
82 * @param test Document to test
83 * @return Diff object describing differences in documents
84 * @throws SAXException
85 * @throws IOException
86 */
87 public Diff compareXML(InputSource control, InputSource test)
88 throws SAXException, IOException {
89 return XMLUnit.compareXML(control, test);
90 }
91
92 /**
93 * Compare XML documents provided by two Reader classes
94 * @param control Control document
95 * @param test Document to test
96 * @return Diff object describing differences in documents
97 * @throws SAXException
98 * @throws IOException
99 */
100 public Diff compareXML(Reader control, Reader test)
101 throws SAXException, IOException {
102 return XMLUnit.compareXML(control, test);
103 }
104
105 /**
106 * Compare XML documents provided by two Reader classes
107 * @param control Control document
108 * @param test Document to test
109 * @return Diff object describing differences in documents
110 * @throws SAXException
111 * @throws IOException
112 */
113 public Diff compareXML(String control, Reader test)
114 throws SAXException, IOException {
115 return XMLUnit.compareXML(new StringReader(control), test);
116 }
117
118 /**
119 * Compare XML documents provided by two Reader classes
120 * @param control Control document
121 * @param test Document to test
122 * @return Diff object describing differences in documents
123 * @throws SAXException
124 * @throws IOException
125 */
126 public Diff compareXML(Reader control, String test)
127 throws SAXException, IOException {
128 return XMLUnit.compareXML(control, new StringReader(test));
129 }
130
131 /**
132 * Compare two XML documents provided as strings
133 * @param control Control document
134 * @param test Document to test
135 * @return Diff object describing differences in documents
136 * @throws SAXException
137 * @throws IOException
138 */
139 public Diff compareXML(String control, String test)
140 throws SAXException, IOException {
141 return XMLUnit.compareXML(control, test);
142 }
143
144 /**
145 * Compare two XML documents provided as strings
146 * @param control Control document
147 * @param test Document to test
148 * @return Diff object describing differences in documents
149 */
150 public Diff compareXML(Document control, Document test) {
151 return XMLUnit.compareXML(control, test);
152 }
153
154 /**
155 * Assert that the result of an XML comparison is or is not similar.
156 * @param diff the result of an XML comparison
157 * @param assertion true if asserting that result is similar
158 */
159 public void assertXMLEqual(Diff diff, boolean assertion) {
160 XMLAssert.assertXMLEqual(diff, assertion);
161 }
162
163 /**
164 * Assert that the result of an XML comparison is or is not similar.
165 * @param msg additional message to display if assertion fails
166 * @param diff the result of an XML comparison
167 * @param assertion true if asserting that result is similar
168 */
169 public void assertXMLEqual(String msg, Diff diff, boolean assertion) {
170 XMLAssert.assertXMLEqual(msg, diff, assertion);
171 }
172
173 /**
174 * Assert that the result of an XML comparison is or is not identical
175 * @param diff the result of an XML comparison
176 * @param assertion true if asserting that result is identical
177 */
178 public void assertXMLIdentical(Diff diff, boolean assertion) {
179 XMLAssert.assertXMLIdentical(diff.toString(), diff, assertion);
180 }
181
182 /**
183 * Assert that the result of an XML comparison is or is not identical
184 * @param msg Message to display if assertion fails
185 * @param diff the result of an XML comparison
186 * @param assertion true if asserting that result is identical
187 */
188 public void assertXMLIdentical(String msg, Diff diff, boolean assertion) {
189 XMLAssert.assertXMLIdentical(msg, diff, assertion);
190 }
191
192 /**
193 * Assert that two XML documents are similar
194 * @param control XML to be compared against
195 * @param test XML to be tested
196 * @throws SAXException
197 * @throws IOException
198 */
199 public void assertXMLEqual(InputSource control, InputSource test)
200 throws SAXException, IOException {
201 XMLAssert.assertXMLEqual(control, test);
202 }
203
204 /**
205 * Assert that two XML documents are similar
206 * @param control XML to be compared against
207 * @param test XML to be tested
208 * @throws SAXException
209 * @throws IOException
210 */
211 public void assertXMLEqual(String control, String test)
212 throws SAXException, IOException {
213 XMLAssert.assertXMLEqual(control, test);
214 }
215
216 /**
217 * Assert that two XML documents are similar
218 * @param control XML to be compared against
219 * @param test XML to be tested
220 */
221 public void assertXMLEqual(Document control, Document test) {
222 XMLAssert.assertXMLEqual(control, test);
223 }
224
225 /**
226 * Assert that two XML documents are similar
227 * @param control XML to be compared against
228 * @param test XML to be tested
229 * @throws SAXException
230 * @throws IOException
231 */
232 public void assertXMLEqual(Reader control, Reader test)
233 throws SAXException, IOException {
234 XMLAssert.assertXMLEqual(control, test);
235 }
236
237 /**
238 * Assert that two XML documents are similar
239 * @param err Message to be displayed on assertion failure
240 * @param control XML to be compared against
241 * @param test XML to be tested
242 * @throws SAXException
243 * @throws IOException
244 */
245 public void assertXMLEqual(String err, String control, String test)
246 throws SAXException, IOException {
247 XMLAssert.assertXMLEqual(err, control, test);
248 }
249
250 /**
251 * Assert that two XML documents are similar
252 * @param err Message to be displayed on assertion failure
253 * @param control XML to be compared against
254 * @param test XML to be tested
255 * @throws SAXException
256 * @throws IOException
257 */
258 public void assertXMLEqual(String err, InputSource control,
259 InputSource test)
260 throws SAXException, IOException {
261 XMLAssert.assertXMLEqual(err, control, test);
262 }
263
264 /**
265 * Assert that two XML documents are similar
266 * @param err Message to be displayed on assertion failure
267 * @param control XML to be compared against
268 * @param test XML to be tested
269 */
270 public void assertXMLEqual(String err, Document control, Document test) {
271 XMLAssert.assertXMLEqual(err, control, test);
272 }
273
274 /**
275 * Assert that two XML documents are similar
276 * @param err Message to be displayed on assertion failure
277 * @param control XML to be compared against
278 * @param test XML to be tested
279 * @throws SAXException
280 * @throws IOException
281 */
282 public void assertXMLEqual(String err, Reader control, Reader test)
283 throws SAXException, IOException {
284 XMLAssert.assertXMLEqual(err, control, test);
285 }
286
287 /**
288 * Assert that two XML documents are NOT similar
289 * @param control XML to be compared against
290 * @param test XML to be tested
291 * @throws SAXException
292 * @throws IOException
293 */
294 public void assertXMLNotEqual(InputSource control, InputSource test)
295 throws SAXException, IOException {
296 XMLAssert.assertXMLNotEqual(control, test);
297 }
298
299 /**
300 * Assert that two XML documents are NOT similar
301 * @param control XML to be compared against
302 * @param test XML to be tested
303 * @throws SAXException
304 * @throws IOException
305 */
306 public void assertXMLNotEqual(String control, String test)
307 throws SAXException, IOException {
308 XMLAssert.assertXMLNotEqual(control, test);
309 }
310
311 /**
312 * Assert that two XML documents are NOT similar
313 * @param control XML to be compared against
314 * @param test XML to be tested
315 */
316 public void assertXMLNotEqual(Document control, Document test) {
317 XMLAssert.assertXMLNotEqual(control, test);
318 }
319
320 /**
321 * Assert that two XML documents are NOT similar
322 * @param control XML to be compared against
323 * @param test XML to be tested
324 * @throws SAXException
325 * @throws IOException
326 */
327 public void assertXMLNotEqual(Reader control, Reader test)
328 throws SAXException, IOException {
329 XMLAssert.assertXMLNotEqual(control, test);
330 }
331
332 /**
333 * Assert that two XML documents are NOT similar
334 * @param err Message to be displayed on assertion failure
335 * @param control XML to be compared against
336 * @param test XML to be tested
337 * @throws SAXException
338 * @throws IOException
339 */
340 public void assertXMLNotEqual(String err, InputSource control,
341 InputSource test)
342 throws SAXException, IOException {
343 XMLAssert.assertXMLNotEqual(err, control, test);
344 }
345
346 /**
347 * Assert that two XML documents are NOT similar
348 * @param err Message to be displayed on assertion failure
349 * @param control XML to be compared against
350 * @param test XML to be tested
351 * @throws SAXException
352 * @throws IOException
353 */
354 public void assertXMLNotEqual(String err, String control, String test)
355 throws SAXException, IOException {
356 XMLAssert.assertXMLNotEqual(err, control, test);
357 }
358
359 /**
360 * Assert that two XML documents are NOT similar
361 * @param err Message to be displayed on assertion failure
362 * @param control XML to be compared against
363 * @param test XML to be tested
364 */
365 public void assertXMLNotEqual(String err, Document control, Document test) {
366 XMLAssert.assertXMLNotEqual(err, control, test);
367 }
368
369 /**
370 * Assert that two XML documents are NOT similar
371 * @param err Message to be displayed on assertion failure
372 * @param control XML to be compared against
373 * @param test XML to be tested
374 * @throws SAXException
375 * @throws IOException
376 */
377 public void assertXMLNotEqual(String err, Reader control, Reader test)
378 throws SAXException, IOException {
379 XMLAssert.assertXMLNotEqual(err, control, test);
380 }
381
382 /**
383 * Assert that the node lists of two Xpaths in the same document are equal
384 * @param xpathOne
385 * @param xpathTwo
386 * @param document
387 * @see XpathEngine
388 */
389 public void assertXpathsEqual(String controlXpath, String testXpath,
390 InputSource document)
391 throws SAXException, IOException, XpathException {
392 XMLAssert.assertXpathsEqual(controlXpath, testXpath, document);
393 }
394
395 /**
396 * Assert that the node lists of two Xpaths in the same document are equal
397 * @param xpathOne
398 * @param xpathTwo
399 * @param document
400 * @see XpathEngine
401 */
402 public void assertXpathsEqual(String controlXpath, String testXpath,
403 Document document)
404 throws XpathException {
405 XMLAssert.assertXpathsEqual(controlXpath, testXpath, document);
406 }
407
408 /**
409 * Assert that the node lists of two Xpaths in the same XML string are
410 * equal
411 * @param xpathOne
412 * @param xpathTwo
413 * @param inXMLString
414 * @throws SAXException
415 * @throws IOException
416 */
417 public void assertXpathsEqual(String controlXpath, String testXpath,
418 String inXMLString)
419 throws SAXException, IOException, XpathException {
420 XMLAssert.assertXpathsEqual(controlXpath, testXpath, inXMLString);
421 }
422
423 /**
424 * Assert that the node lists of two Xpaths in two XML pieces are equal
425 * @param xpathOne
426 * @param control
427 * @param xpathTwo
428 * @param test
429 * @throws SAXException
430 * @throws IOException
431 */
432 public void assertXpathsEqual(String controlXpath, InputSource control,
433 String testXpath, InputSource test)
434 throws SAXException, IOException, XpathException {
435 XMLAssert.assertXpathsEqual(controlXpath, control,
436 testXpath, test);
437 }
438
439 /**
440 * Assert that the node lists of two Xpaths in two XML strings are equal
441 * @param xpathOne
442 * @param inControlXMLString
443 * @param xpathTwo
444 * @param inTestXMLString
445 * @throws SAXException
446 * @throws IOException
447 */
448 public void assertXpathsEqual(String controlXpath,
449 String inControlXMLString, String testXpath,
450 String inTestXMLString)
451 throws SAXException, IOException,
452 XpathException {
453 XMLAssert.assertXpathsEqual(controlXpath, inControlXMLString,
454 testXpath, inTestXMLString);
455 }
456
457 /**
458 * Assert that the node lists of two Xpaths in two documents are equal
459 * @param xpathOne
460 * @param xpathTwo
461 * @param document
462 * @see XpathEngine
463 */
464 public void assertXpathsEqual(String controlXpath,
465 Document controlDocument,
466 String testXpath, Document testDocument)
467 throws XpathException {
468 XMLAssert.assertXpathsEqual(controlXpath, controlDocument, testXpath,
469 testDocument);
470 }
471
472 /**
473 * Assert that the node lists of two Xpaths in the same document are NOT equal
474 * @param xpathOne
475 * @param xpathTwo
476 * @param document
477 * @see XpathEngine
478 */
479 public void assertXpathsNotEqual(String controlXpath, String testXpath,
480 Document document)
481 throws XpathException {
482 XMLAssert.assertXpathsNotEqual(controlXpath, testXpath, document);
483 }
484
485 /**
486 * Assert that the node lists of two Xpaths in the same XML are NOT
487 * equal
488 * @param xpathOne
489 * @param xpathTwo
490 * @param control
491 * @throws SAXException
492 * @throws IOException
493 */
494 public void assertXpathsNotEqual(String controlXpath, String testXpath,
495 InputSource control)
496 throws SAXException, IOException, XpathException {
497 XMLAssert.assertXpathsNotEqual(controlXpath, testXpath, control);
498 }
499
500 /**
501 * Assert that the node lists of two Xpaths in the same XML string are NOT
502 * equal
503 * @param xpathOne
504 * @param xpathTwo
505 * @param inXMLString
506 * @throws SAXException
507 * @throws IOException
508 */
509 public void assertXpathsNotEqual(String controlXpath, String testXpath,
510 String inXMLString)
511 throws SAXException,
512 IOException, XpathException {
513 XMLAssert.assertXpathsNotEqual(controlXpath, testXpath, inXMLString);
514 }
515
516 /**
517 * Assert that the node lists of two Xpaths in two pieces of XML
518 * are NOT equal
519 * @param xpathOne
520 * @param control
521 * @param xpathTwo
522 * @param test
523 * @throws SAXException
524 * @throws IOException
525 */
526 public void assertXpathsNotEqual(String controlXpath, InputSource control,
527 String testXpath, InputSource test)
528 throws SAXException, IOException, XpathException {
529 XMLAssert.assertXpathsNotEqual(controlXpath, control, testXpath, test);
530 }
531
532 /**
533 * Assert that the node lists of two Xpaths in two XML strings are NOT equal
534 * @param xpathOne
535 * @param inControlXMLString
536 * @param xpathTwo
537 * @param inTestXMLString
538 * @throws SAXException
539 * @throws IOException
540 */
541 public void assertXpathsNotEqual(String controlXpath,
542 String inControlXMLString,
543 String testXpath, String inTestXMLString)
544 throws SAXException, IOException,
545 XpathException {
546 XMLAssert.assertXpathsNotEqual(controlXpath, inControlXMLString,
547 testXpath, inTestXMLString);
548 }
549
550 /**
551 * Assert that the node lists of two Xpaths in two documents are NOT equal
552 * @param xpathOne
553 * @param xpathTwo
554 * @param document
555 * @see XpathEngine
556 */
557 public void assertXpathsNotEqual(String controlXpath,
558 Document controlDocument,
559 String testXpath, Document testDocument)
560 throws XpathException {
561 XMLAssert.assertXpathsNotEqual(controlXpath, controlDocument,
562 testXpath, testDocument);
563 }
564
565 /**
566 * Assert that the evaluation of two Xpaths in the same document are equal
567 * @param xpathOne
568 * @param xpathTwo
569 * @param document
570 * @see XpathEngine
571 */
572 public void assertXpathValuesEqual(String controlXpath, String testXpath,
573 Document document)
574 throws XpathException {
575 XMLAssert.assertXpathValuesEqual(controlXpath, testXpath, document);
576 }
577
578 /**
579 * Assert that the evaluation of two Xpaths in the same XML are
580 * equal
581 * @param xpathOne
582 * @param xpathTwo
583 * @param control
584 * @throws SAXException
585 * @throws IOException
586 */
587 public void assertXpathValuesEqual(String controlXpath, String testXpath,
588 InputSource control)
589 throws SAXException, IOException, XpathException {
590 XMLAssert.assertXpathValuesEqual(controlXpath, testXpath, control);
591 }
592
593 /**
594 * Assert that the evaluation of two Xpaths in the same XML string are
595 * equal
596 * @param xpathOne
597 * @param xpathTwo
598 * @param inXMLString
599 * @throws SAXException
600 * @throws IOException
601 */
602 public void assertXpathValuesEqual(String controlXpath, String testXpath,
603 String inXMLString)
604 throws SAXException, IOException,
605 XpathException {
606 XMLAssert.assertXpathValuesEqual(controlXpath, testXpath, inXMLString);
607 }
608
609 /**
610 * Assert that the evaluation of two Xpaths in two XML strings are equal
611 * @param xpathOne
612 * @param control
613 * @param xpathTwo
614 * @param test
615 * @throws SAXException
616 * @throws IOException
617 */
618 public void assertXpathValuesEqual(String controlXpath,
619 InputSource control,
620 String testXpath,
621 InputSource test)
622 throws SAXException, IOException, XpathException {
623 XMLAssert.assertXpathValuesEqual(controlXpath, control,
624 testXpath, test);
625 }
626
627 /**
628 * Assert that the evaluation of two Xpaths in two XML strings are equal
629 * @param xpathOne
630 * @param inControlXMLString
631 * @param xpathTwo
632 * @param inTestXMLString
633 * @throws SAXException
634 * @throws IOException
635 */
636 public void assertXpathValuesEqual(String controlXpath,
637 String inControlXMLString,
638 String testXpath,
639 String inTestXMLString)
640 throws SAXException, IOException,
641 XpathException {
642 XMLAssert.assertXpathValuesEqual(controlXpath, inControlXMLString,
643 testXpath, inTestXMLString);
644 }
645
646 /**
647 * Assert that the evaluation of two Xpaths in two documents are equal
648 * @param xpathOne
649 * @param xpathTwo
650 * @param document
651 * @see XpathEngine
652 */
653 public void assertXpathValuesEqual(String controlXpath,
654 Document controlDocument,
655 String testXpath, Document testDocument)
656 throws XpathException {
657 XMLAssert.assertXpathValuesEqual(controlXpath, controlDocument,
658 testXpath, testDocument);
659 }
660
661 /**
662 * Assert that the evaluation of two Xpaths in the same XML string are
663 * NOT equal
664 * @param xpathOne
665 * @param xpathTwo
666 * @param control
667 * @throws SAXException
668 * @throws IOException
669 */
670 public void assertXpathValuesNotEqual(String controlXpath,
671 String testXpath,
672 InputSource control)
673 throws SAXException, IOException, XpathException {
674 XMLAssert.assertXpathValuesNotEqual(controlXpath, testXpath,
675 control);
676 }
677
678 /**
679 * Assert that the evaluation of two Xpaths in the same XML string are
680 * NOT equal
681 * @param xpathOne
682 * @param xpathTwo
683 * @param inXMLString
684 * @throws SAXException
685 * @throws IOException
686 */
687 public void assertXpathValuesNotEqual(String controlXpath, String testXpath,
688 String inXMLString)
689 throws SAXException, IOException,
690 XpathException {
691 XMLAssert.assertXpathValuesNotEqual(controlXpath, testXpath,
692 inXMLString);
693 }
694
695 /**
696 * Assert that the evaluation of two Xpaths in the same document are
697 * NOT equal
698 * @param xpathOne
699 * @param xpathTwo
700 * @param document
701 */
702 public void assertXpathValuesNotEqual(String controlXpath, String testXpath,
703 Document document)
704 throws XpathException {
705 XMLAssert.assertXpathValuesNotEqual(controlXpath, testXpath, document);
706 }
707
708 /**
709 * Assert that the evaluation of two Xpaths in two XML strings are
710 * NOT equal
711 * @param xpathOne
712 * @param control
713 * @param xpathTwo
714 * @param test
715 * @throws SAXException
716 * @throws IOException
717 */
718 public void assertXpathValuesNotEqual(String controlXpath,
719 InputSource control,
720 String testXpath,
721 InputSource test)
722 throws SAXException, IOException, XpathException {
723 XMLAssert.assertXpathValuesNotEqual(controlXpath, control,
724 testXpath, test);
725 }
726
727 /**
728 * Assert that the evaluation of two Xpaths in two XML strings are
729 * NOT equal
730 * @param xpathOne
731 * @param inControlXMLString
732 * @param xpathTwo
733 * @param inTestXMLString
734 * @throws SAXException
735 * @throws IOException
736 */
737 public void assertXpathValuesNotEqual(String controlXpath,
738 String inControlXMLString,
739 String testXpath,
740 String inTestXMLString)
741 throws SAXException, IOException,
742 XpathException {
743 XMLAssert.assertXpathValuesNotEqual(controlXpath, inControlXMLString,
744 testXpath, inTestXMLString);
745 }
746
747 /**
748 * Assert that the evaluation of two Xpaths in two documents are
749 * NOT equal
750 * @param xpathOne
751 * @param xpathTwo
752 * @param document
753 */
754 public void assertXpathValuesNotEqual(String controlXpath,
755 Document controlDocument,
756 String testXpath,
757 Document testDocument)
758 throws XpathException {
759 XMLAssert.assertXpathValuesNotEqual(controlXpath, controlDocument,
760 testXpath, testDocument);
761 }
762
763 /**
764 * Assert the value of an Xpath expression in an XML String
765 * @param expectedValue
766 * @param xpathExpression
767 * @param control
768 * @throws SAXException
769 * @throws IOException
770 * @see XpathEngine which provides the underlying evaluation mechanism
771 */
772 public void assertXpathEvaluatesTo(String expectedValue,
773 String xpathExpression,
774 InputSource control)
775 throws SAXException, IOException, XpathException {
776 XMLAssert.assertXpathEvaluatesTo(expectedValue, xpathExpression,
777 control);
778 }
779
780 /**
781 * Assert the value of an Xpath expression in an XML String
782 * @param expectedValue
783 * @param xpathExpression
784 * @param inXMLString
785 * @throws SAXException
786 * @throws IOException
787 * @see XpathEngine which provides the underlying evaluation mechanism
788 */
789 public void assertXpathEvaluatesTo(String expectedValue,
790 String xpathExpression,
791 String inXMLString)
792 throws SAXException, IOException,
793 XpathException {
794 XMLAssert.assertXpathEvaluatesTo(expectedValue, xpathExpression,
795 inXMLString);
796 }
797
798 /**
799 * Assert the value of an Xpath expression in an DOM Document
800 * @param expectedValue
801 * @param xpathExpression
802 * @param inDocument
803 * @param ctx
804 * @see XpathEngine which provides the underlying evaluation mechanism
805 */
806 public void assertXpathEvaluatesTo(String expectedValue,
807 String xpathExpression,
808 Document inDocument)
809 throws XpathException {
810 XMLAssert.assertXpathEvaluatesTo(expectedValue, xpathExpression,
811 inDocument);
812 }
813
814 /**
815 * Assert that a specific XPath exists in some given XML
816 * @param inXpathExpression
817 * @param xml
818 * @see XpathEngine which provides the underlying evaluation mechanism
819 */
820 public void assertXpathExists(String xPathExpression,
821 InputSource xml)
822 throws IOException, SAXException, XpathException {
823 XMLAssert.assertXpathExists(xPathExpression, xml);
824 }
825
826 /**
827 * Assert that a specific XPath exists in some given XML
828 * @param inXpathExpression
829 * @param inXMLString
830 * @see XpathEngine which provides the underlying evaluation mechanism
831 */
832 public void assertXpathExists(String xPathExpression,
833 String inXMLString)
834 throws IOException, SAXException, XpathException {
835 XMLAssert.assertXpathExists(xPathExpression, inXMLString);
836 }
837
838 /**
839 * Assert that a specific XPath exists in some given XML
840 * @param inXpathExpression
841 * @param inDocument
842 * @param ctx
843 * @see XpathEngine which provides the underlying evaluation mechanism
844 */
845 public void assertXpathExists(String xPathExpression, Document inDocument)
846 throws XpathException {
847 XMLAssert.assertXpathExists(xPathExpression, inDocument);
848 }
849
850 /**
851 * Assert that a specific XPath does NOT exist in some given XML
852 * @param inXpathExpression
853 * @param xml
854 * @see XpathEngine which provides the underlying evaluation mechanism
855 */
856 public void assertXpathNotExists(String xPathExpression,
857 InputSource xml)
858 throws IOException, SAXException, XpathException {
859 XMLAssert.assertXpathNotExists(xPathExpression, xml);
860 }
861
862 /**
863 * Assert that a specific XPath does NOT exist in some given XML
864 * @param inXpathExpression
865 * @param inXMLString
866 * @see XpathEngine which provides the underlying evaluation mechanism
867 */
868 public void assertXpathNotExists(String xPathExpression,
869 String inXMLString)
870 throws IOException, SAXException, XpathException {
871 XMLAssert.assertXpathNotExists(xPathExpression, inXMLString);
872 }
873
874 /**
875 * Assert that a specific XPath does NOT exist in some given XML
876 * @param inXpathExpression
877 * @param inDocument
878 * @see XpathEngine which provides the underlying evaluation mechanism
879 */
880 public void assertXpathNotExists(String xPathExpression,
881 Document inDocument)
882 throws XpathException {
883 XMLAssert.assertXpathNotExists(xPathExpression, inDocument);
884 }
885
886 /**
887 * Assert that a piece of XML contains valid XML: the input must
888 * contain a DOCTYPE declaration to be validated
889 * @param xml
890 * @throws SAXException
891 * @throws ConfigurationException if validation could not be turned on
892 * @see Validator
893 */
894 public void assertXMLValid(InputSource xml)
895 throws SAXException, ConfigurationException {
896 XMLAssert.assertXMLValid(xml);
897 }
898
899 /**
900 * Assert that a String containing XML contains valid XML: the String must
901 * contain a DOCTYPE declaration to be validated
902 * @param xmlString
903 * @throws SAXException
904 * @throws ConfigurationException if validation could not be turned on
905 * @see Validator
906 */
907 public void assertXMLValid(String xmlString)
908 throws SAXException, ConfigurationException {
909 XMLAssert.assertXMLValid(xmlString);
910 }
911
912 /**
913 * Assert that a piece of XML contains valid XML: the document must
914 * contain a DOCTYPE to be validated, but the validation will use the
915 * systemId to obtain the DTD
916 * @param xml
917 * @param systemId
918 * @throws SAXException
919 * @throws ConfigurationException if validation could not be turned on
920 * @see Validator
921 */
922 public void assertXMLValid(InputSource xml, String systemId)
923 throws SAXException, ConfigurationException {
924 XMLAssert.assertXMLValid(xml, systemId);
925 }
926
927 /**
928 * Assert that a String containing XML contains valid XML: the String must
929 * contain a DOCTYPE to be validated, but the validation will use the
930 * systemId to obtain the DTD
931 * @param xmlString
932 * @param systemId
933 * @throws SAXException
934 * @throws ConfigurationException if validation could not be turned on
935 * @see Validator
936 */
937 public void assertXMLValid(String xmlString, String systemId)
938 throws SAXException, ConfigurationException {
939 XMLAssert.assertXMLValid(xmlString, systemId);
940 }
941
942 /**
943 * Assert that a piece of XML contains valid XML: the document
944 * will be given a DOCTYPE to be validated with the name and
945 * systemId specified regardless of whether it already contains a
946 * doctype declaration.
947 * @param xml
948 * @param systemId
949 * @param doctype
950 * @throws SAXException
951 * @throws ConfigurationException if validation could not be turned on
952 * @see Validator
953 */
954 public void assertXMLValid(InputSource xml, String systemId,
955 String doctype)
956 throws SAXException, ConfigurationException {
957 XMLAssert.assertXMLValid(xml, systemId, doctype);
958 }
959
960 /**
961 * Assert that a String containing XML contains valid XML: the String will
962 * be given a DOCTYPE to be validated with the name and systemId specified
963 * regardless of whether it already contains a doctype declaration.
964 * @param xmlString
965 * @param systemId
966 * @param doctype
967 * @throws SAXException
968 * @throws ConfigurationException if validation could not be turned on
969 * @see Validator
970 */
971 public void assertXMLValid(String xmlString, String systemId, String doctype)
972 throws SAXException, ConfigurationException {
973 XMLAssert.assertXMLValid(xmlString, systemId, doctype);
974 }
975
976 /**
977 * Assert that a Validator instance returns <code>isValid() == true</code>
978 * @param validator
979 */
980 public void assertXMLValid(Validator validator) {
981 XMLAssert.assertXMLValid(validator);
982 }
983
984 /**
985 * Execute a <code>NodeTest<code> for a single node type
986 * and assert that it passes
987 * @param xml XML to be tested
988 * @param tester The test strategy
989 * @param nodeType The node type to be tested: constants defined
990 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
991 * @throws SAXException
992 * @throws IOException
993 * @see AbstractNodeTester
994 * @see CountingNodeTester
995 */
996 public void assertNodeTestPasses(InputSource xml, NodeTester tester,
997 short nodeType)
998 throws SAXException, IOException {
999 XMLAssert.assertNodeTestPasses(xml, tester, nodeType);
1000 }
1001
1002 /**
1003 * Execute a <code>NodeTest<code> for a single node type
1004 * and assert that it passes
1005 * @param xmlString XML to be tested
1006 * @param tester The test strategy
1007 * @param nodeType The node type to be tested: constants defined
1008 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
1009 * @throws SAXException
1010 * @throws IOException
1011 * @see AbstractNodeTester
1012 * @see CountingNodeTester
1013 */
1014 public void assertNodeTestPasses(String xmlString, NodeTester tester,
1015 short nodeType)
1016 throws SAXException, IOException {
1017 XMLAssert.assertNodeTestPasses(xmlString, tester, nodeType);
1018 }
1019
1020 /**
1021 * Execute a <code>NodeTest<code> for multiple node types and make an
1022 * assertion about it whether it is expected to pass
1023 * @param test a NodeTest instance containing the XML source to be tested
1024 * @param tester The test strategy
1025 * @param nodeTypes The node types to be tested: constants defined
1026 * in {@link Node org.w3c.dom.Node} e.g. <code>Node.ELEMENT_NODE</code>
1027 * @param assertion true if the test is expected to pass, false otherwise
1028 * @see AbstractNodeTester
1029 * @see CountingNodeTester
1030 */
1031 public void assertNodeTestPasses(NodeTest test, NodeTester tester,
1032 short[] nodeTypes, boolean assertion) {
1033 XMLAssert.assertNodeTestPasses(test, tester, nodeTypes, assertion);
1034 }
1035 }
0 /*
1 *****************************************************************
2 Copyright (c) 2001-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
39 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
40
41 import javax.xml.parsers.DocumentBuilder;
42 import javax.xml.parsers.DocumentBuilderFactory;
43 import javax.xml.parsers.ParserConfigurationException;
44 import javax.xml.parsers.SAXParserFactory;
45 import javax.xml.transform.TransformerException;
46 import javax.xml.transform.TransformerFactory;
47 import javax.xml.transform.URIResolver;
48
49 import java.io.IOException;
50 import java.io.Reader;
51 import java.io.StringReader;
52 import java.text.NumberFormat;
53 import java.text.ParseException;
54 import java.util.Locale;
55 import org.w3c.dom.Document;
56 import org.w3c.dom.Node;
57 import org.w3c.dom.NodeList;
58 import org.xml.sax.InputSource;
59 import org.xml.sax.SAXException;
60 import org.xml.sax.EntityResolver;
61
62 /**
63 * Allows access to project control parameters such as which Parser to use and
64 * provides some convenience methods for building Documents from Strings etc.
65 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
66 */
67 public final class XMLUnit {
68 private static DocumentBuilderFactory controlBuilderFactory;
69 private static DocumentBuilderFactory testBuilderFactory;
70 private static TransformerFactory transformerFactory;
71 private static SAXParserFactory saxParserFactory;
72 private static boolean ignoreWhitespace = false;
73 private static URIResolver uriResolver = null;
74 private static EntityResolver testEntityResolver = null;
75 private static EntityResolver controlEntityResolver = null;
76 private static NamespaceContext namespaceContext = null;
77 private static boolean ignoreDiffBetweenTextAndCDATA = false;
78 private static boolean ignoreComments = false;
79 private static boolean normalize = false;
80 private static boolean normalizeWhitespace = false;
81 private static boolean ignoreAttributeOrder = false;
82 private static String xsltVersion = "1.0";
83 private static String xpathFactoryName = null;
84 private static boolean expandEntities = false;
85 private static boolean compareUnmatched = true;
86
87 private static final String XSLT_VERSION_START = " version=\"";
88 private static final String XSLT_VERSION_END = "\">";
89
90 private static final String STRIP_WHITESPACE_STYLESHEET_START
91 = new StringBuffer(XMLConstants.XML_DECLARATION)
92 .append(XSLTConstants.XSLT_START_NO_VERSION)
93 .append(XSLT_VERSION_START)
94 .toString();
95
96 private static final String STRIP_WHITESPACE_STYLESHEET_END
97 = new StringBuffer(XSLT_VERSION_END)
98 .append(XSLTConstants.XSLT_XML_OUTPUT_NOINDENT)
99 .append(XSLTConstants.XSLT_STRIP_WHITESPACE)
100 .append(XSLTConstants.XSLT_IDENTITY_TEMPLATE)
101 .append(XSLTConstants.XSLT_END)
102 .toString();
103
104 private static final String STRIP_COMMENTS_STYLESHEET_START
105 = new StringBuffer(XMLConstants.XML_DECLARATION)
106 .append(XSLTConstants.XSLT_START_NO_VERSION)
107 .append(XSLT_VERSION_START)
108 .toString();
109
110 private static final String STRIP_COMMENTS_STYLESHEET_END
111 = new StringBuffer(XSLT_VERSION_END)
112 .append(XSLTConstants.XSLT_XML_OUTPUT_NOINDENT)
113 .append(XSLTConstants.XSLT_STRIP_COMMENTS_TEMPLATE)
114 .append(XSLTConstants.XSLT_END)
115 .toString();
116
117 /**
118 * Private constructor.
119 * Makes class non-instantiable
120 */
121 private XMLUnit() {
122 // access via static methods please
123 }
124
125 /**
126 * Overide the DocumentBuilder to use to parse control documents.
127 * This is useful when comparing the output of two different
128 * parsers. Note: setting the control parser before any test cases
129 * are run will affect the test parser as well.
130 */
131 public static void setControlParser(String className) {
132 System.setProperty("javax.xml.parsers.DocumentBuilderFactory", className);
133 controlBuilderFactory = null;
134 controlBuilderFactory = getControlDocumentBuilderFactory();
135 }
136 /**
137 * Get the <code>DocumentBuilder</code> instance used to parse the control
138 * XML in an XMLTestCase.
139 * @return parser for control values
140 * @throws ConfigurationException
141 */
142 public static DocumentBuilder newControlParser()
143 throws ConfigurationException {
144 try {
145 controlBuilderFactory = getControlDocumentBuilderFactory();
146 DocumentBuilder builder =
147 controlBuilderFactory.newDocumentBuilder();
148 if (controlEntityResolver!=null) {
149 builder.setEntityResolver(controlEntityResolver);
150 }
151 return builder;
152 } catch (ParserConfigurationException ex) {
153 throw new ConfigurationException(ex);
154 }
155 }
156
157 /**
158 * Sets an EntityResolver to be added to all new test parsers.
159 * Setting to null will reset to the default EntityResolver
160 */
161 public static void setTestEntityResolver(EntityResolver resolver) {
162 testEntityResolver = resolver;
163 }
164
165 /**
166 * Sets an EntityResolver to be added to all new control parsers.
167 * Setting to null will reset to the default EntityResolver
168 */
169 public static void setControlEntityResolver(EntityResolver resolver) {
170 controlEntityResolver = resolver;
171 }
172
173 /**
174 * Obtains the EntityResolver to be added to all new control parsers.
175 */
176 public static EntityResolver getControlEntityResolver() {
177 return controlEntityResolver;
178 }
179
180 /**
181 * Get the <code>DocumentBuilderFactory</code> instance used to instantiate
182 * parsers for the control XML in an XMLTestCase.
183 * @return factory for control parsers
184 */
185 public static DocumentBuilderFactory getControlDocumentBuilderFactory() {
186 if (controlBuilderFactory == null) {
187 controlBuilderFactory = DocumentBuilderFactory.newInstance();
188 controlBuilderFactory.setNamespaceAware(true);
189 }
190 return controlBuilderFactory;
191 }
192 /**
193 * Override the <code>DocumentBuilderFactory</code> used to instantiate
194 * parsers for the control XML in an XMLTestCase.
195 */
196 public static void setControlDocumentBuilderFactory(DocumentBuilderFactory factory) {
197 if (factory == null) {
198 throw new IllegalArgumentException("Cannot set control DocumentBuilderFactory to null!");
199 }
200 controlBuilderFactory = factory;
201 }
202
203 /**
204 * Overide the DocumentBuilder to use to parser test documents.
205 * This is useful when comparing the output of two different
206 * parsers. Note: setting the test parser before any test cases
207 * are run will affect the control parser as well.
208 */
209 public static void setTestParser(String className) {
210 System.setProperty("javax.xml.parsers.DocumentBuilderFactory", className);
211 testBuilderFactory = null;
212 testBuilderFactory = getTestDocumentBuilderFactory();
213 }
214 /**
215 * Get the <code>DocumentBuilder</code> instance used to parse the test XML
216 * in an XMLTestCase.
217 * @return parser for test values
218 * @throws ConfigurationException
219 */
220 public static DocumentBuilder newTestParser()
221 throws ConfigurationException {
222 try {
223 testBuilderFactory = getTestDocumentBuilderFactory();
224 DocumentBuilder builder = testBuilderFactory.newDocumentBuilder();
225 if (testEntityResolver!=null) {
226 builder.setEntityResolver(testEntityResolver);
227 }
228 return builder;
229 } catch (ParserConfigurationException ex) {
230 throw new ConfigurationException(ex);
231 }
232 }
233
234 /**
235 * Get the <code>DocumentBuilder</code> instance used to parse the test XML
236 * in an XMLTestCase.
237 * @return parser for test values
238 * @throws ConfigurationException
239 * @deprecated use newTestParser()
240 */
241 public static DocumentBuilder getTestParser()
242 throws ConfigurationException {
243 return newTestParser();
244 }
245
246 /**
247 * Get the <code>DocumentBuilder</code> instance used to parse the test XML
248 * in an XMLTestCase.
249 * @return parser for control values
250 * @deprecated use newControlParser()
251 * @throws ConfigurationException
252 */
253 public static DocumentBuilder getControlParser()
254 throws ConfigurationException {
255 return newControlParser();
256 }
257
258 /**
259 * Get the <code>DocumentBuilderFactory</code> instance used to instantiate
260 * parsers for the test XML in an XMLTestCase.
261 * @return factory for test parsers
262 */
263 public static DocumentBuilderFactory getTestDocumentBuilderFactory() {
264 if (testBuilderFactory == null) {
265 testBuilderFactory = DocumentBuilderFactory.newInstance();
266 testBuilderFactory.setNamespaceAware(true);
267 }
268 return testBuilderFactory;
269 }
270 /**
271 * Override the <code>DocumentBuilderFactory</code> used to instantiate
272 * parsers for the test XML in an XMLTestCase.
273 */
274 public static void setTestDocumentBuilderFactory(DocumentBuilderFactory factory) {
275 if (factory == null) {
276 throw new IllegalArgumentException("Cannot set test DocumentBuilderFactory to null!");
277 }
278 testBuilderFactory = factory;
279 }
280
281 /**
282 * Whether to ignore whitespace when comparing node values.
283 *
284 * <p>This method also invokes
285 * <code>setIgnoringElementContentWhitespace()</code> on the
286 * underlying control AND test document builder factories.</p>
287 *
288 * <p>Setting this parameter has no effect on {@link
289 * setNormalizeWhitespace whitespace inside texts}.</p>
290 */
291 public static void setIgnoreWhitespace(boolean ignore){
292 ignoreWhitespace = ignore;
293 getControlDocumentBuilderFactory().setIgnoringElementContentWhitespace(ignore);
294 getTestDocumentBuilderFactory().setIgnoringElementContentWhitespace(ignore);
295 }
296
297 /**
298 * Whether to ignore whitespace when comparing node values.
299 * @return true if whitespace should be ignored when comparing nodes, false
300 * otherwise
301 */
302 public static boolean getIgnoreWhitespace(){
303 return ignoreWhitespace;
304 }
305
306 /**
307 * Utility method to build a Document using the control DocumentBuilder
308 * to parse the specified String.
309 * @param fromXML
310 * @return Document representation of the String content
311 * @throws SAXException
312 * @throws IOException
313 */
314 public static Document buildControlDocument(String fromXML)
315 throws SAXException, IOException {
316 return buildDocument(newControlParser(), new StringReader(fromXML));
317 }
318
319 /**
320 * Utility method to build a Document using the control DocumentBuilder
321 * and the specified InputSource
322 * @param fromSource
323 * @return Document representation of the String content
324 * @throws SAXException
325 * @throws IOException
326 */
327 public static Document buildControlDocument(InputSource fromSource)
328 throws IOException, SAXException {
329 return buildDocument(newControlParser(), fromSource);
330 }
331
332 /**
333 * Utility method to build a Document using the test DocumentBuilder
334 * to parse the specified String.
335 * @param fromXML
336 * @return Document representation of the String content
337 * @throws SAXException
338 * @throws IOException
339 */
340 public static Document buildTestDocument(String fromXML)
341 throws SAXException, IOException {
342 return buildDocument(newTestParser(), new StringReader(fromXML));
343 }
344
345 /**
346 * Utility method to build a Document using the test DocumentBuilder
347 * and the specified InputSource
348 * @param fromSource
349 * @return Document representation of the String content
350 * @throws SAXException
351 * @throws IOException
352 */
353 public static Document buildTestDocument(InputSource fromSource)
354 throws IOException, SAXException {
355 return buildDocument(newTestParser(), fromSource);
356 }
357
358 /**
359 * Utility method to build a Document using a specific DocumentBuilder
360 * and reading characters from a specific Reader.
361 * @param withBuilder
362 * @param fromReader
363 * @return Document built
364 * @throws SAXException
365 * @throws IOException
366 */
367 public static Document buildDocument(DocumentBuilder withBuilder,
368 Reader fromReader) throws SAXException, IOException {
369 return buildDocument(withBuilder, new InputSource(fromReader));
370 }
371 /**
372 * Utility method to build a Document using a specific DocumentBuilder
373 * and a specific InputSource
374 * @param withBuilder
375 * @param fromSource
376 * @return Document built
377 * @throws SAXException
378 * @throws IOException
379 */
380 public static Document buildDocument(DocumentBuilder withBuilder,
381 InputSource fromSource) throws IOException, SAXException {
382 return withBuilder.parse(fromSource);
383 }
384
385 /**
386 * Overide the transformer to use for XSLT transformations (and by
387 * implication serialization and XPaths).
388 * This is useful when comparing transformer implementations.
389 */
390 public static void setTransformerFactory(String className) {
391 System.setProperty("javax.xml.transform.TransformerFactory",
392 className);
393 transformerFactory = null;
394 getTransformerFactory();
395 }
396
397 /**
398 * Get the transformer to use for XSLT transformations (and by
399 * implication serialization and XPaths).
400 * @return the current transformer factory in use
401 * a new instance of the default transformer factory
402 */
403 public static TransformerFactory getTransformerFactory() {
404 if (transformerFactory == null) {
405 transformerFactory = newTransformerFactory();
406 }
407 return transformerFactory;
408 }
409
410 /**
411 * Get a fresh transformer to use for XSLT transformations (and by
412 * implication serialization and XPaths).
413 * @return a new instance of the default transformer factory
414 */
415 static TransformerFactory newTransformerFactory() {
416 TransformerFactory tf = TransformerFactory.newInstance();
417 if (uriResolver != null) {
418 tf.setURIResolver(uriResolver);
419 }
420 return tf;
421 }
422
423 /**
424 * Sets the URIResolver to use during transformations.
425 */
426 public static void setURIResolver(URIResolver resolver) {
427 if (uriResolver != resolver) {
428 uriResolver = resolver;
429 transformerFactory = null;
430 getTransformerFactory();
431 }
432 }
433
434 /**
435 * Gets the URIResolver used during Transformations.
436 */
437 public static URIResolver getURIResolver() {
438 return uriResolver;
439 }
440
441 /**
442 * Override the SAX parser to use in tests.
443 * Currently only used by {@link Validator Validator class}
444 * @param className
445 */
446 public static void setSAXParserFactory(String className) {
447 System.setProperty("javax.xml.parsers.SAXParserFactory", className);
448 saxParserFactory = null;
449 getSAXParserFactory();
450 }
451
452 /**
453 * Override the SAX parser to use in tests.
454 * Currently only used by {@link Validator Validator class}
455 * @param factory
456 */
457 public static void setSAXParserFactory(SAXParserFactory factory) {
458 saxParserFactory = factory;
459 }
460
461 /**
462 * Get the SAX parser to use in tests.
463 *
464 * <p>Unless an instance has been given via {@link
465 * setSAXParserFactory(SAXParserFactory) setSAXParserFactory}
466 * explicitly, the returned factory will be namespace aware.</p>
467 *
468 * @return the SAXParserFactory instance used by the {@link
469 * Validator Validator} to perform DTD validation
470 */
471 public static SAXParserFactory getSAXParserFactory() {
472 if (saxParserFactory == null) {
473 saxParserFactory = SAXParserFactory.newInstance();
474 saxParserFactory.setNamespaceAware(true);
475 }
476 return saxParserFactory;
477 }
478
479 private static String getStripWhitespaceStylesheet() {
480 return STRIP_WHITESPACE_STYLESHEET_START + getXSLTVersion()
481 + STRIP_WHITESPACE_STYLESHEET_END;
482 }
483
484 /**
485 * Obtain the transformation that will strip whitespace from a DOM
486 * containing empty Text nodes
487 * @param forDocument
488 * @return a <code>Transform</code> to do the whitespace stripping
489 */
490 public static Transform getStripWhitespaceTransform(Document forDocument) {
491 return new Transform(forDocument, getStripWhitespaceStylesheet());
492 }
493
494 /**
495 * Returns a new Document instance that is identical to the one
496 * passed in with element content whitespace removed.
497 *
498 * <p>Will use {@link #getStripWhitespaceTransform
499 * getStripWhitespaceTransform} unless we are operating under the
500 * severly broken XSLTC Transformer shipping with JDK 1.5.</p>
501 */
502 public static Document getWhitespaceStrippedDocument(Document forDoc) {
503 String factory = getTransformerFactory().getClass().getName();
504 if (XSLTConstants.JAVA5_XSLTC_FACTORY_NAME.equals(factory)) {
505 return stripWhiteSpaceWithoutXSLT(forDoc);
506 } else {
507 return stripWhiteSpaceUsingXSLT(forDoc);
508 }
509 }
510
511 private static Document stripWhiteSpaceUsingXSLT(Document forDoc) {
512 try {
513 Transform whitespaceStripper = getStripWhitespaceTransform(forDoc);
514 return whitespaceStripper.getResultDocument();
515 } catch (TransformerException e) {
516 throw new XMLUnitRuntimeException(e.getMessage(), e.getCause());
517 }
518 }
519
520 private static Document stripWhiteSpaceWithoutXSLT(Document forDoc) {
521 Document copy = (Document) forDoc.cloneNode(true);
522 stripEmptyTextNodes(copy);
523 return copy;
524 }
525
526 private static void stripEmptyTextNodes(Node n) {
527 final NodeList nl = n.getChildNodes();
528 for (int i = 0; i < nl.getLength(); i++) {
529 Node child = nl.item(i);
530 if (child.getNodeType() == Node.ELEMENT_NODE) {
531 stripEmptyTextNodes(child);
532 } else if (child.getNodeType() == Node.TEXT_NODE) {
533 String value = child.getNodeValue();
534 if (value == null || value.trim().length() == 0) {
535 n.removeChild(child);
536 --i;
537 }
538 }
539 }
540 }
541
542 private static String getStripCommentsStylesheet() {
543 return STRIP_COMMENTS_STYLESHEET_START + getXSLTVersion()
544 + STRIP_COMMENTS_STYLESHEET_END;
545 }
546
547 /**
548 * Obtain the transformation that will strip comments from a DOM.
549 * @param forDocument
550 * @return a <code>Transform</code> to do the whitespace stripping
551 */
552 public static Transform getStripCommentsTransform(Document forDocument) {
553 return new Transform(forDocument, getStripCommentsStylesheet());
554 }
555
556 /**
557 * Place holder for current version info.
558 * @return current version
559 */
560 public static String getVersion() {
561 return "1.3alpha";
562 }
563
564 /**
565 * Compare XML documents provided by two InputSource classes
566 * @param control Control document
567 * @param test Document to test
568 * @return Diff object describing differences in documents
569 * @throws SAXException
570 * @throws IOException
571 */
572 public static Diff compareXML(InputSource control, InputSource test)
573 throws SAXException, IOException {
574 return new Diff(control, test);
575 }
576
577 /**
578 * Compare XML documents provided by two Reader classes
579 * @param control Control document
580 * @param test Document to test
581 * @return Diff object describing differences in documents
582 * @throws SAXException
583 * @throws IOException
584 */
585 public static Diff compareXML(Reader control, Reader test)
586 throws SAXException, IOException {
587 return new Diff(control, test);
588 }
589
590 /**
591 * Compare XML documents provided by two Reader classes
592 * @param control Control document
593 * @param test Document to test
594 * @return Diff object describing differences in documents
595 * @throws SAXException
596 * @throws IOException
597 */
598 public static Diff compareXML(String control, Reader test)
599 throws SAXException, IOException {
600 return new Diff(new StringReader(control), test);
601 }
602
603 /**
604 * Compare XML documents provided by two Reader classes
605 * @param control Control document
606 * @param test Document to test
607 * @return Diff object describing differences in documents
608 * @throws SAXException
609 * @throws IOException
610 */
611 public static Diff compareXML(Reader control, String test)
612 throws SAXException, IOException {
613 return new Diff(control, new StringReader(test));
614 }
615
616 /**
617 * Compare two XML documents provided as strings
618 * @param control Control document
619 * @param test Document to test
620 * @return Diff object describing differences in documents
621 * @throws SAXException
622 * @throws IOException
623 */
624 public static Diff compareXML(String control, String test)
625 throws SAXException, IOException {
626 return new Diff(control, test);
627 }
628
629 /**
630 * Compare two XML documents provided as strings
631 * @param control Control document
632 * @param test Document to test
633 * @return Diff object describing differences in documents
634 */
635 public static Diff compareXML(Document control, Document test) {
636 return new Diff(control, test);
637 }
638
639 /**
640 * Get the NamespaceContext to use in XPath tests.
641 */
642 public static NamespaceContext getXpathNamespaceContext() {
643 return namespaceContext;
644 }
645
646 /**
647 * Set the NamespaceContext to use in XPath tests.
648 */
649 public static void setXpathNamespaceContext(NamespaceContext ctx) {
650 namespaceContext = ctx;
651 }
652
653 /**
654 * Obtains an XpathEngine to use in XPath tests.
655 */
656 public static XpathEngine newXpathEngine() {
657 XpathEngine eng = null;
658 try {
659 Class.forName("javax.xml.xpath.XPath");
660 Class c = Class.forName("org.custommonkey.xmlunit.jaxp13"
661 + ".Jaxp13XpathEngine");
662 eng = (XpathEngine) c.newInstance();
663 } catch (Throwable ex) {
664 // should probably only catch ClassNotFoundException, but some
665 // constellations - like Ant shipping a more recent version of
666 // xml-apis than the JDK - may contain the JAXP 1.3 interfaces
667 // without implementations
668 eng = new SimpleXpathEngine();
669 }
670 if (namespaceContext != null) {
671 eng.setNamespaceContext(namespaceContext);
672 }
673 return eng;
674 }
675
676 /**
677 * Whether CDATA sections and Text nodes should be considered the same.
678 *
679 * <p>The default is false.</p>
680 *
681 * <p>This also set the DocumentBuilderFactory's {@link
682 * javax.xml.parsers.DocumentBuilderFactory#setCoalescing
683 * coalescing} flag on the factories for the control and test
684 * document.</p>
685 */
686 public static void setIgnoreDiffBetweenTextAndCDATA(boolean b) {
687 ignoreDiffBetweenTextAndCDATA = b;
688 getControlDocumentBuilderFactory().setCoalescing(b);
689 getTestDocumentBuilderFactory().setCoalescing(b);
690 }
691
692 /**
693 * Whether CDATA sections and Text nodes should be considered the same.
694 *
695 * <p>The default is false.</p>
696 */
697 public static boolean getIgnoreDiffBetweenTextAndCDATA() {
698 return ignoreDiffBetweenTextAndCDATA;
699 }
700
701 /**
702 * Whether comments should be ignored.
703 *
704 * <p>The default value is false</p>
705 */
706 public static void setIgnoreComments(boolean b) {
707 ignoreComments = b;
708 }
709
710 /**
711 * Whether comments should be ignored.
712 *
713 * <p>The default value is false</p>
714 */
715 public static boolean getIgnoreComments() {
716 return ignoreComments;
717 }
718
719 /**
720 * Whether Text nodes should be normalized.
721 *
722 * <p>The default value is false</p>
723 *
724 * <p><b>Note:</b> if you are only working with documents read
725 * from streams (like files or network connections) or working
726 * with strings, there is no reason to change the default since
727 * the XML parser is required to normalize the documents. If you
728 * are testing {@link org.w3c.Document Document} instances you've
729 * created in code, you may want to alter the default
730 * behavior.</p>
731 *
732 * <p><b>Note2:</b> depending on the XML parser or XSLT
733 * transformer you use, setting {@link setIgnoreWhitespace
734 * ignoreWhitespace} or {@link setIgnoreComments ignoreComments}
735 * to true may have already normalized your document and this
736 * setting doesn't have any effect anymore.</p>
737 */
738 public static void setNormalize(boolean b) {
739 normalize = b;
740 }
741
742 /**
743 * Whether Text nodes should be normalized.
744 *
745 * <p>The default value is false</p>
746 */
747 public static boolean getNormalize() {
748 return normalize;
749 }
750
751 /**
752 * Whether whitespace characters inside text nodes or attributes
753 * should be "normalized".
754 *
755 * <p>Normalized in this context means that all whitespace is
756 * replaced by the space character and adjacent whitespace
757 * characters are collapsed to a single space character. It will
758 * also trim the resulting character content on both ends.</p>
759 *
760 * <p>The default value is false.</p>
761 *
762 * <p>Setting this parameter has no effect on {@link
763 * setIgnoreWhitespace ignorable whitespace}.</p>
764 */
765 public static void setNormalizeWhitespace(boolean b) {
766 normalizeWhitespace = b;
767 }
768
769 /**
770 * Whether whitespace characters inside text nodes or attributes
771 * should be "normalized".
772 *
773 * <p>Normalized in this context means that all whitespace is
774 * replaced by the space character and adjacent whitespace
775 * characters are collapsed to a single space character.</p>
776 *
777 * <p>The default value is false.</p>
778 */
779 public static boolean getNormalizeWhitespace() {
780 return normalizeWhitespace;
781 }
782
783 /**
784 * Whether to ignore the order of attributes on an element.
785 *
786 * <p>The order of attributes has never been relevant for XML
787 * documents, still XMLUnit will consider two pieces of XML
788 * not-identical (but similar) if they differ in order of
789 * attributes. Set this option to false to ignore the order.</p>
790 *
791 * <p>The default value is false for backwards compatibility
792 * reasons.</p>
793 */
794 public static void setIgnoreAttributeOrder(boolean b) {
795 ignoreAttributeOrder = b;
796 }
797
798 /**
799 * Whether to ignore the order of attributes on an element.
800 *
801 * <p>The order of attributes has never been relevant for XML
802 * documents, still XMLUnit will consider two pieces of XML
803 * not-identical (but similar) if they differ in order of
804 * attributes. Set this option to false to ignore the order.</p>
805 *
806 * <p>The default value is false for backwards compatibility
807 * reasons.</p>
808 */
809 public static boolean getIgnoreAttributeOrder() {
810 return ignoreAttributeOrder;
811 }
812
813 /**
814 * Sets the XSLT version to set on stylesheets used internally.
815 *
816 * <p>Defaults to "1.0".</p>
817 *
818 * @throws ConfigurationException if the argument cannot be parsed
819 * as a positive number.
820 */
821 public static void setXSLTVersion(String s) {
822 try {
823 Number n = NumberFormat.getInstance(Locale.US).parse(s);
824 if (n.doubleValue() < 0) {
825 throw new ConfigurationException(s + " doesn't reperesent a"
826 + " positive number.");
827 }
828 } catch (ParseException e) {
829 throw new ConfigurationException(e);
830 }
831 xsltVersion = s;
832 }
833
834 /**
835 * The XSLT version set on stylesheets used internally.
836 *
837 * <p>Defaults to "1.0".</p>
838 */
839 public static String getXSLTVersion() {
840 return xsltVersion;
841 }
842
843 /**
844 * Sets the class to use as XPathFactory when using JAXP 1.3.
845 */
846 public static void setXPathFactory(String className) {
847 xpathFactoryName = className;
848 }
849
850 /**
851 * Gets the class to use as XPathFactory when using JAXP 1.3.
852 */
853 public static String getXPathFactory() {
854 return xpathFactoryName;
855 }
856
857 /**
858 * XSLT stylesheet element using the configured XSLT version.
859 */
860 static String getXSLTStart() {
861 return XSLTConstants.XSLT_START_NO_VERSION
862 + XSLT_VERSION_START + getXSLTVersion() + XSLT_VERSION_END;
863 }
864
865 /**
866 * Whether the parser shall be instructed to expand entity references.
867 *
868 * <p>Defaults to false.</p>
869 *
870 * @see javax.xml.parsers.DocumentBuilderFactory#setExpandEntityReferences
871 */
872 public static void setExpandEntityReferences(boolean b) {
873 expandEntities = b;
874 getControlDocumentBuilderFactory().setExpandEntityReferences(b);
875 getTestDocumentBuilderFactory().setExpandEntityReferences(b);
876 }
877
878 /**
879 * Whether the parser shall be instructed to expand entity references.
880 */
881 public static boolean getExpandEntityReferences() {
882 return expandEntities;
883 }
884
885 /**
886 * Whether to compare unmatched control nodes to unmatched test nodes.
887 *
888 * <p>Defaults to true.</p>
889 */
890 public static void setCompareUnmatched(boolean b) {
891 compareUnmatched = b;
892 }
893
894 /**
895 * Whether unmatched control nodes should be compared to unmatched
896 * test nodes.
897 */
898 public static boolean getCompareUnmatched() {
899 return compareUnmatched;
900 }
901 }
902
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * A convenient place to hang constants relating to XSL transformations
40 */
41 public interface XSLTConstants extends XMLConstants {
42 /**
43 * &lt;xsl:stylesheet
44 */
45 String XSLT_START_NO_VERSION =
46 "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"";
47
48 /**
49 * &lt;xsl:stylesheet ... version="1.0"&gt;
50 */
51 String XSLT_START =
52 XSLT_START_NO_VERSION + " version=\"1.0\">";
53
54 /**
55 * &lt;xsl:output&gt; for XML with no indentation
56 */
57 String XSLT_XML_OUTPUT_NOINDENT =
58 "<xsl:output method=\"xml\" version=\"1.0\" indent=\"no\"/>";
59
60 /**
61 * &lt;xsl:strip-space&gt; for all elements
62 */
63 String XSLT_STRIP_WHITESPACE =
64 "<xsl:strip-space elements=\"*\"/>";
65
66 /**
67 * &lt;xsl:template&gt; to copy the current nodeset into the output tree
68 */
69 String XSLT_IDENTITY_TEMPLATE =
70 "<xsl:template match=\"/\"><xsl:copy-of select=\".\"/></xsl:template>";
71
72 /**
73 * &lt;xsl:template&gt; to copy the current nodeset into the
74 * output tree while stripping comments.
75 */
76 String XSLT_STRIP_COMMENTS_TEMPLATE =
77 "<xsl:template match=\"node()[not(self::comment())]|@*\">"
78 + "<xsl:copy><xsl:apply-templates select=\"node()[not(self::comment())]|@*\"/></xsl:copy>"
79 + "</xsl:template>";
80
81 /**
82 * &lt;/xsl:stylesheet&gt;
83 */
84 String XSLT_END = "</xsl:stylesheet>";
85
86 /**
87 * Factory class of the XSLTC version shipping with JDK 1.5 which
88 * is pretty broken.
89 */
90 String JAVA5_XSLTC_FACTORY_NAME =
91 "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
92 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.custommonkey.xmlunit.exceptions.XpathException;
39
40 import org.w3c.dom.Document;
41 import org.w3c.dom.NodeList;
42
43 /**
44 * Abstraction of an engine evaluating XPath expressions.
45 */
46 public interface XpathEngine {
47
48 /**
49 * Execute the specified xpath syntax <code>select</code> expression
50 * on the specified document and return the list of nodes (could have
51 * length zero) that match
52 * @param select
53 * @param document
54 * @return list of matching nodes
55 */
56 NodeList getMatchingNodes(String select, Document document)
57 throws XpathException;
58
59 /**
60 * Evaluate the result of executing the specified xpath syntax
61 * <code>select</code> expression on the specified document
62 * @param select
63 * @param document
64 * @return evaluated result
65 */
66 String evaluate(String select, Document document)
67 throws XpathException;
68
69 /**
70 * Establish a namespace context.
71 */
72 void setNamespaceContext(NamespaceContext ctx);
73 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit;
36
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42
43 import org.w3c.dom.Attr;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.NodeList;
47
48 /**
49 * Tracks Nodes visited by the DifferenceEngine and
50 * converts that information into an Xpath-String to supply
51 * to the NodeDetail of a Difference instance
52 * @see NodeDetail#getXpathLocation()
53 * @see Difference#getControlNodeDetail
54 * @see Difference#getTestNodeDetail
55 */
56 public class XpathNodeTracker implements XMLConstants {
57 private final List indentationList = new ArrayList();
58 private TrackingEntry currentEntry;
59
60 /**
61 * Simple constructor
62 */
63 public XpathNodeTracker() {
64 newLevel();
65 }
66
67 /**
68 * Clear state data.
69 * Call if required to reuse an existing instance.
70 */
71 public void reset() {
72 indentationList.clear();
73 indent();
74 }
75
76 /**
77 * Call before examining child nodes one level of indentation into DOM
78 */
79 public void indent() {
80 if (currentEntry != null) {
81 currentEntry.clearTrackedAttribute();
82 }
83 newLevel();
84 }
85
86 private void newLevel() {
87 currentEntry = new TrackingEntry();
88 indentationList.add(currentEntry);
89 }
90
91 /**
92 * Call after processing attributes of an element and turining to
93 * compare the child nodes.
94 */
95 public void clearTrackedAttribute() {
96 if (currentEntry != null) {
97 currentEntry.clearTrackedAttribute();
98 }
99 }
100
101 /**
102 * Call after examining child nodes, ie before returning back one level of indentation from DOM
103 */
104 public void outdent() {
105 int last = indentationList.size() - 1;
106 indentationList.remove(last);
107 --last;
108 if (last >= 0) {
109 currentEntry = (TrackingEntry) indentationList.get(last);
110 }
111 }
112
113 /**
114 * Call when visiting a node whose xpath location needs tracking
115 * @param node the Node being visited
116 */
117 public void visited(Node node) {
118 String nodeName;
119 switch(node.getNodeType()) {
120 case Node.ATTRIBUTE_NODE:
121 nodeName = ((Attr)node).getLocalName();
122 if (nodeName == null || nodeName.length() == 0) {
123 nodeName = node.getNodeName();
124 }
125 visitedAttribute(nodeName);
126 break;
127 case Node.ELEMENT_NODE:
128 nodeName = ((Element)node).getLocalName();
129 if (nodeName == null || nodeName.length() == 0) {
130 nodeName = node.getNodeName();
131 }
132 visitedNode(node, nodeName);
133 break;
134 case Node.COMMENT_NODE:
135 visitedNode(node, XPATH_COMMENT_IDENTIFIER);
136 break;
137 case Node.PROCESSING_INSTRUCTION_NODE:
138 visitedNode(node, XPATH_PROCESSING_INSTRUCTION_IDENTIFIER);
139 break;
140 case Node.CDATA_SECTION_NODE:
141 case Node.TEXT_NODE:
142 visitedNode(node, XPATH_CHARACTER_NODE_IDENTIFIER);
143 break;
144 default:
145 // ignore unhandled node types
146 break;
147 }
148 }
149
150 protected void visitedNode(Node visited, String value) {
151 currentEntry.trackNode(visited, value);
152 }
153
154 protected void visitedAttribute(String visited) {
155 currentEntry.trackAttribute(visited);
156 }
157
158 /**
159 * Preload the items in a NodeList by visiting each in turn
160 * Required for pieces of test XML whose node children can be visited
161 * out of sequence by a DifferenceEngine comparison
162 * @param nodeList the items to preload
163 */
164 public void preloadNodeList(NodeList nodeList) {
165 currentEntry.trackNodesAsWellAsValues(true);
166 int length = nodeList.getLength();
167 for (int i=0; i < length; ++i) {
168 visited(nodeList.item(i));
169 }
170 currentEntry.trackNodesAsWellAsValues(false);
171 }
172
173 /**
174 * Preload the items in a List by visiting each in turn
175 * Required for pieces of test XML whose node children can be visited
176 * out of sequence by a DifferenceEngine comparison
177 * @param nodeList the items to preload
178 */
179 public void preloadChildList(List nodeList) {
180 currentEntry.trackNodesAsWellAsValues(true);
181 int length = nodeList.size();
182 for (int i=0; i < length; ++i) {
183 visited((Node) nodeList.get(i));
184 }
185 currentEntry.trackNodesAsWellAsValues(false);
186 }
187
188 /**
189 * @return the last visited node as an xpath-location String
190 */
191 public String toXpathString() {
192 StringBuffer buf = new StringBuffer();
193 TrackingEntry nextEntry;
194 for (Iterator iter = indentationList.iterator(); iter.hasNext(); ) {
195 nextEntry = (TrackingEntry) iter.next();
196 nextEntry.appendEntryTo(buf);
197 }
198 return buf.toString();
199 }
200
201 /**
202 * Wrapper class around a mutable <code>int</code> value
203 * Avoids creation of many immutable <code>Integer</code> objects
204 */
205 private static final class Int {
206 private int value;
207
208 public Int(int startAt) {
209 value = startAt;
210 }
211
212 public void increment() {
213 ++value;
214 }
215
216 public int getValue() {
217 return value;
218 }
219
220 public Integer toInteger() {
221 return new Integer(value);
222 }
223 }
224
225 /**
226 * Holds node tracking details - one instance is used for each level of indentation in a DOM
227 * Provides reference between a String-ified Node value and the xpath index of that value
228 */
229 private static final class TrackingEntry {
230 private final Map valueMap = new HashMap();
231 private String currentValue, currentAttribute;
232
233 private Map nodeReferenceMap;
234 private boolean trackNodeReferences = false;
235 private Integer nodeReferenceLookup = null;
236
237 private Int lookup(String value) {
238 return (Int) valueMap.get(value);
239 }
240
241 /**
242 * Keep a reference to the current visited (non-attribute) node
243 * @param visited the non-attribute node visited
244 * @param value the String-ified value of the non-attribute node visited
245 */
246 public void trackNode(Node visited, String value) {
247 if (nodeReferenceMap == null || trackNodeReferences) {
248 Int occurrence = lookup(value);
249 if (occurrence == null) {
250 occurrence = new Int(1);
251 valueMap.put(value, occurrence);
252 } else {
253 occurrence.increment();
254 }
255 if (trackNodeReferences) {
256 nodeReferenceMap.put(visited, occurrence.toInteger());
257 }
258 } else {
259 nodeReferenceLookup = (Integer) nodeReferenceMap.get(visited);
260 }
261 currentValue = value;
262 clearTrackedAttribute();
263 }
264
265 /**
266 * Keep a reference to the visited attribute at the current visited node
267 * @param value the attribute visited
268 */
269 public void trackAttribute(String visited) {
270 currentAttribute = visited;
271 }
272
273 /**
274 * Clear any reference to the current visited attribute
275 */
276 public void clearTrackedAttribute() {
277 currentAttribute = null;
278 }
279
280 /**
281 * Append the details of the current visited node to a StringBuffer
282 * @param buf the StringBuffer to append to
283 */
284 public void appendEntryTo(StringBuffer buf) {
285 if (currentValue == null) {
286 return;
287 }
288 buf.append(XPATH_SEPARATOR).append(currentValue);
289
290 int value = nodeReferenceLookup == null
291 ? lookup(currentValue).getValue() : nodeReferenceLookup.intValue();
292 buf.append(XPATH_NODE_INDEX_START).append(value).append(XPATH_NODE_INDEX_END);
293
294 if (currentAttribute != null) {
295 buf.append(XPATH_SEPARATOR).append(XPATH_ATTRIBUTE_IDENTIFIER)
296 .append(currentAttribute);
297 }
298 }
299
300 public void trackNodesAsWellAsValues(boolean yesNo) {
301 this.trackNodeReferences = yesNo;
302 if (yesNo) {
303 nodeReferenceMap = new HashMap();
304 }
305 }
306 }
307 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import java.util.Locale;
38 import org.custommonkey.xmlunit.Difference;
39 import org.custommonkey.xmlunit.DifferenceListener;
40
41 /**
42 * Ignores case for all textual content.
43 */
44 public class CaseInsensitiveDifferenceListener
45 extends TextDifferenceListenerBase {
46
47 public CaseInsensitiveDifferenceListener(DifferenceListener delegateTo) {
48 super(delegateTo);
49 }
50
51 protected int textualDifference(Difference d) {
52 String control = d.getControlNodeDetail().getValue();
53 if (control != null) {
54 control = control.toLowerCase(Locale.US);
55 if (d.getTestNodeDetail().getValue() != null
56 && control.equals(d.getTestNodeDetail().getValue()
57 .toLowerCase(Locale.US))) {
58 return
59 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
60 }
61 }
62 // some string is null, delegate
63 return super.textualDifference(d);
64 }
65 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import org.custommonkey.xmlunit.NodeTest;
39 import org.custommonkey.xmlunit.NodeTestException;
40 import org.custommonkey.xmlunit.NodeTester;
41 import org.w3c.dom.Node;
42
43 /**
44 * Counts the number of nodes in a document to allow assertions to be made
45 * using a NodeTest.
46 * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
47 * @see NodeTest
48 */
49 public class CountingNodeTester implements NodeTester {
50 private final int expectedNumNodes;
51 private int actualNumNodes;
52
53 public CountingNodeTester(int expectedNumNodes) {
54 this.expectedNumNodes = expectedNumNodes;
55 }
56
57 /**
58 * A single Node is always valid
59 * @param aNode
60 * @param forTest
61 */
62 public void testNode(Node aNode, NodeTest forTest) {
63 actualNumNodes++;
64 }
65
66 /**
67 * Called by NodeTest when all nodes have been iterated over: time to see
68 * if all the nodes that were expected were found.
69 * Note that this method also invokes {@link #resetCounter resetCounter}
70 * so that the instance can be reused.
71 * @exception true if expected num nodes == actual num nodes,
72 * false otherwise
73 */
74 public void noMoreNodes(NodeTest forTest) throws NodeTestException {
75 int testedNodes = actualNumNodes;
76 resetCounter();
77 if (testedNodes != expectedNumNodes) {
78 throw new NodeTestException("Counted " + testedNodes
79 + " node(s) but expected " + expectedNumNodes);
80 }
81 }
82
83 /**
84 * Reset the counter so that an instance can be reused for another
85 * <code>NodeTest</code>
86 */
87 public void resetCounter() {
88 actualNumNodes = 0;
89 }
90 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008,2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import org.custommonkey.xmlunit.Difference;
38 import org.custommonkey.xmlunit.DifferenceListener;
39
40 /**
41 * Expects texts to be floating point numbers and treats them as
42 * identical if they only differ by a given tolerance value (or less).
43 *
44 * <p>This implementation uses an absolute tolerance value value for
45 * all numbers encountered, calculating a difference relative to one
46 * of the numbers compared might be more appropriate in general.</p>
47 */
48 public class FloatingPointTolerantDifferenceListener
49 extends TextDifferenceListenerBase {
50
51 private final double tolerance;
52
53 public FloatingPointTolerantDifferenceListener(DifferenceListener delegateTo,
54 double tolerance) {
55 super(delegateTo);
56 this.tolerance = tolerance;
57 }
58
59 protected int textualDifference(Difference d) {
60 String control = d.getControlNodeDetail().getValue();
61 String test = d.getTestNodeDetail().getValue();
62 if (control != null && test != null) {
63 try {
64 double controlVal = Double.parseDouble(control);
65 double testVal = Double.parseDouble(test);
66 return Math.abs(controlVal - testVal) <= tolerance
67 ? DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
68 : DifferenceListener.RETURN_ACCEPT_DIFFERENCE;
69 } catch (NumberFormatException nfe) {
70 // ignore, delegate to nested DifferenceListener
71 }
72 }
73 // no numbers or null, delegate
74 return super.textualDifference(d);
75 }
76 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import org.w3c.dom.Element;
39 import org.w3c.dom.Node;
40
41 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
42 import org.custommonkey.xmlunit.ElementNameQualifier;
43 import org.custommonkey.xmlunit.ElementQualifier;
44
45 /**
46 * Per popular request an interface implementation that uses element
47 * names and the text node containes in the n'th child node to compare
48 * elements.
49 *
50 * <p>This means {@link ElementNameAndTextQualifier
51 * ElementNameQualifier} and MultiLevelElementNameQualifier(1) should
52 * lead to the same results.</p>
53 *
54 * <p>Any attribute values are completely ignored. Only works on
55 * elements with exactly one child element at each level.</p>
56 *
57 * <p>This class mostly exists as an example for custom ElementQualifiers.</p>
58 */
59 public class MultiLevelElementNameAndTextQualifier
60 implements ElementQualifier {
61
62 private final int levels;
63 private final boolean ignoreEmptyTexts;
64
65 private static final ElementNameQualifier NAME_QUALIFIER =
66 new ElementNameQualifier();
67 private static final ElementNameAndTextQualifier NAME_AND_TEXT_QUALIFIER =
68 new ElementNameAndTextQualifier();
69
70 /**
71 * Uses element names and the text nested <code>levels</code>
72 * child elements deeper into the element to compare elements.
73 *
74 * <p>Does not ignore empty text nodes.
75 */
76 public MultiLevelElementNameAndTextQualifier(int levels) {
77 this(levels, false);
78 }
79
80 /**
81 * Uses element names and the text nested <code>levels</code>
82 * child elements deeper into the element to compare elements.
83 *
84 * @param ignoreEmptyTexts whether whitespace-only textnodes
85 * should be ignored.
86 */
87 public MultiLevelElementNameAndTextQualifier(int levels,
88 boolean ignoreEmptyTexts) {
89 if (levels < 1) {
90 throw new IllegalArgumentException("levels must be equal or"
91 + " greater than one");
92 }
93 this.levels = levels;
94 this.ignoreEmptyTexts = ignoreEmptyTexts;
95 }
96
97 public boolean qualifyForComparison(Element control, Element test) {
98 boolean stillSimilar = true;
99 Element currentControl = control;
100 Element currentTest = test;
101
102 // match on element names only for leading levels
103 for (int currentLevel = 0; stillSimilar && currentLevel <= levels - 2;
104 currentLevel++) {
105 stillSimilar = NAME_QUALIFIER.qualifyForComparison(currentControl,
106 currentTest);
107
108 if (stillSimilar) {
109 if (currentControl.hasChildNodes()
110 && currentTest.hasChildNodes()) {
111 Node n1 = getFirstEligibleChild(currentControl);
112 Node n2 = getFirstEligibleChild(currentTest);
113 if (n1.getNodeType() == Node.ELEMENT_NODE
114 && n2.getNodeType() == Node.ELEMENT_NODE) {
115 currentControl = (Element) n1;
116 currentTest = (Element) n2;
117 } else {
118 stillSimilar = false;
119 }
120 } else {
121 stillSimilar = false;
122 }
123 }
124 }
125
126 // finally compare the level containing the text child node
127 if (stillSimilar) {
128 stillSimilar = NAME_AND_TEXT_QUALIFIER
129 .qualifyForComparison(currentControl, currentTest);
130 }
131
132 return stillSimilar;
133 }
134
135 private Node getFirstEligibleChild(Node parent) {
136 Node n1 = parent.getFirstChild();
137 if (ignoreEmptyTexts) {
138 while (n1.getNodeType() == Node.TEXT_NODE
139 && n1.getNodeValue().trim().length() == 0) {
140 Node n2 = n1.getNextSibling();
141 if (n2 == null) break;
142 n1 = n2;
143 }
144 }
145 return n1;
146 }
147 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008,2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import org.w3c.dom.Element;
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41
42 import org.custommonkey.xmlunit.ElementNameQualifier;
43 import org.custommonkey.xmlunit.ElementQualifier;
44
45 /**
46 * Compares all Element and Text nodes in two pieces of XML. Allows elements of
47 * complex, deeply nested types that are returned in different orders but have
48 * the same content to be recognized as comparable.
49 *
50 * @author Frank Callahan
51 */
52 public class RecursiveElementNameAndTextQualifier implements ElementQualifier {
53
54 private static final ElementNameQualifier NAME_QUALIFIER =
55 new ElementNameQualifier();
56
57 /**
58 * Uses element names and the text nested an arbitrary level of
59 * child elements deeper into the element to compare
60 * elements. Checks all nodes, not just first child element.
61 *
62 * <p> Does not ignore empty text nodes.
63 */
64 public RecursiveElementNameAndTextQualifier() {
65 }
66
67 /**
68 * Returns result of recursive comparison of all the nodes of a
69 * control and test element.
70 */
71 public boolean qualifyForComparison(Element currentControl,
72 Element currentTest) {
73 return compareNodes(currentControl, currentTest);
74 }
75
76 private boolean compareNodes(Node currentControl, Node currentTest) {
77 try {
78
79 // if they are elements, compare names of the two nodes
80 if (!NAME_QUALIFIER.qualifyForComparison((Element) currentControl,
81 (Element) currentTest)) {
82 return false;
83 }
84
85 // Compare the control and test elements' children
86
87 NodeList controlNodes = null;
88 NodeList testNodes = null;
89
90 // Check that both nodes have children and, if so, get lists of them
91
92 if (currentControl.hasChildNodes() && currentTest.hasChildNodes()) {
93 controlNodes = currentControl.getChildNodes();
94 testNodes = currentTest.getChildNodes();
95 } else if (currentControl.hasChildNodes()
96 || currentTest.hasChildNodes()) {
97 return false;
98
99 // if both nodes are empty, they are comparable
100 } else {
101 return true;
102 }
103
104 // check that both node lists have the same length
105
106 if (countNodesWithoutConsecutiveTextNodes(controlNodes)
107 != countNodesWithoutConsecutiveTextNodes(testNodes)) {
108 return false;
109 }
110
111 // Do checks of test and control nodes' children
112
113 final int cNodes = controlNodes.getLength();
114 final int tNodes = testNodes.getLength();
115
116 int i, j;
117 for (i = j = 0; i < cNodes && j < tNodes; i++, j++) {
118 Node controlNode = controlNodes.item(i);
119 Node testNode = testNodes.item(j);
120
121 // check if both node are same type
122 if (controlNode.getNodeType() != testNode.getNodeType()) {
123 return false;
124 }
125 // compare text nodes
126 if (controlNode.getNodeType() == Node.TEXT_NODE) {
127 // compare concatenated, trimmed text nodes
128 if (!catText(controlNode).equals(catText(testNode))) {
129 return false;
130 }
131
132 // swallow adjacent Text nodes
133 for (; i < cNodes - 1
134 && controlNodes.item(i + 1).getNodeType() == Node.TEXT_NODE;
135 i++);
136 for (; j < tNodes - 1
137 && testNodes.item(j + 1).getNodeType() == Node.TEXT_NODE;
138 j++);
139
140 // recursive check of current child control and test nodes'
141 // children
142
143 } else if (!compareNodes((Element) controlNode,
144 (Element) testNode)) {
145 return false;
146 }
147 }
148 if (i != cNodes || j != tNodes) {
149 return false;
150 }
151
152 // All descendants of current control and test nodes are comparable
153 return true;
154 } catch (Exception e) {
155 return false;
156 }
157 }
158 /**
159 * Concatenates contiguous Text nodes and removes all leading and
160 * trailing whitespace.
161 * @param textNode
162 * @return
163 */
164 private static String catText(Node textNode) {
165 StringBuffer text = new StringBuffer();
166 Node next = textNode;
167
168 do {
169 if (next.getNodeValue() != null) {
170 text.append(next.getNodeValue().trim());
171 next = next.getNextSibling();
172 }
173 } while (next != null && next.getNodeType() == Node.TEXT_NODE);
174
175 return text.toString();
176 }
177
178 /**
179 * Calculates the number of Nodes that are either not Text nodes
180 * or are Text nodes whose previous sibling isn't a Text node as
181 * well. I.e. consecutive Text nodes are counted as a single
182 * node.
183 */
184 private static int countNodesWithoutConsecutiveTextNodes(NodeList l) {
185 int count = 0;
186 boolean lastNodeWasText = false;
187 final int length = l.getLength();
188 for (int i = 0; i < length; i++) {
189 Node n = l.item(i);
190 if (!lastNodeWasText || n.getNodeType() != Node.TEXT_NODE) {
191 count++;
192 }
193 lastNodeWasText = n.getNodeType() == Node.TEXT_NODE;
194 }
195 return count;
196 }
197 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import org.custommonkey.xmlunit.Difference;
38 import org.custommonkey.xmlunit.DifferenceConstants;
39 import org.custommonkey.xmlunit.DifferenceListener;
40 import org.w3c.dom.Node;
41
42 /**
43 * Base class that delegates all differences to another DifferenceListener.
44 *
45 * <p>Subclasses get a chance to hook into special methods that will
46 * be invoked for differences in textual values of attributes, CDATA
47 * sections, Text or comment nodes.</p>
48 */
49 public abstract class TextDifferenceListenerBase
50 implements DifferenceListener {
51
52 private final DifferenceListener delegateTo;
53
54 protected TextDifferenceListenerBase(DifferenceListener delegateTo) {
55 this.delegateTo = delegateTo;
56 }
57
58 /**
59 * Delegates to the nested DifferenceListener unless the
60 * Difference is of type {@link DifferenceConstants#ATTR_VALUE_ID
61 * ATTR_VALUE_ID}, {@link DifferenceConstants#CDATA_VALUE_ID
62 * CDATA_VALUE_ID}, {@link DifferenceConstants#COMMENT_VALUE_ID
63 * COMMENT_VALUE_ID} or {@link DifferenceConstants#TEXT_VALUE_ID
64 * TEXT_VALUE_ID} - for those special differences {@link
65 * #attributeDifference attributeDifference}, {@link
66 * #cdataDifference cdataDifference}, {@link #commentDifference
67 * commentDifference} or {@link #textDifference textDifference}
68 * are invoked respectively.
69 */
70 public int differenceFound(Difference difference) {
71 switch (difference.getId()) {
72 case DifferenceConstants.ATTR_VALUE_ID:
73 return attributeDifference(difference);
74 case DifferenceConstants.CDATA_VALUE_ID:
75 return cdataDifference(difference);
76 case DifferenceConstants.COMMENT_VALUE_ID:
77 return commentDifference(difference);
78 case DifferenceConstants.TEXT_VALUE_ID:
79 return textDifference(difference);
80 }
81 return delegateTo.differenceFound(difference);
82 }
83
84 /**
85 * Delegates to {@link #textualDifference textualDifference}.
86 */
87 protected int attributeDifference(Difference d) {
88 return textualDifference(d);
89 }
90
91 /**
92 * Delegates to {@link #textualDifference textualDifference}.
93 */
94 protected int cdataDifference(Difference d) {
95 return textualDifference(d);
96 }
97
98 /**
99 * Delegates to {@link #textualDifference textualDifference}.
100 */
101 protected int commentDifference(Difference d) {
102 return textualDifference(d);
103 }
104
105 /**
106 * Delegates to {@link #textualDifference textualDifference}.
107 */
108 protected int textDifference(Difference d) {
109 return textualDifference(d);
110 }
111
112 /**
113 * Delegates to the nested DifferenceListener.
114 */
115 protected int textualDifference(Difference d) {
116 return delegateTo.differenceFound(d);
117 }
118
119 public void skippedComparison(Node control, Node test) {
120 delegateTo.skippedComparison(control, test);
121 }
122
123 }
0 // -*- Mode: JDE -*-
1 /*
2 ******************************************************************
3 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of the xmlunit.sourceforge.net nor the names
17 of its contributors may be used to endorse or promote products
18 derived from this software without specific prior written
19 permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33
34 ******************************************************************
35 */
36 package org.custommonkey.xmlunit.examples;
37
38 import java.io.IOException;
39 import java.io.Reader;
40
41 import org.custommonkey.xmlunit.XpathEngine;
42 import org.custommonkey.xmlunit.XMLUnit;
43 import org.custommonkey.xmlunit.exceptions.XpathException;
44
45 import org.w3c.dom.Document;
46 import org.xml.sax.InputSource;
47 import org.xml.sax.SAXException;
48
49 import junit.framework.Assert;
50
51 /**
52 * Example demonstrating how to use the XPath API of XMLUnit in
53 * conjunction with regular expressions (as provided by the
54 * java.util.regex package of JDK 1.4+).
55 */
56
57 public class XPathRegexAssert {
58 // no instances
59 private XPathRegexAssert() {}
60
61 public static void assertXPathMatches(String message, String regex,
62 String xpath, Document doc)
63 throws XpathException {
64 XpathEngine engine = XMLUnit.newXpathEngine();
65 String value = engine.evaluate(xpath, doc);
66 Assert.assertTrue(message, value.matches(regex));
67 }
68
69 public static void assertXPathMatches(String message, String regex,
70 String xpath, String xml)
71 throws XpathException, SAXException, IOException {
72 Document doc = XMLUnit.buildControlDocument(xml);
73 assertXPathMatches(message, regex, xpath, doc);
74 }
75
76 public static void assertXPathMatches(String message, String regex,
77 String xpath, Reader reader)
78 throws XpathException, SAXException, IOException {
79 Document doc = XMLUnit.buildControlDocument(new InputSource(reader));
80 assertXPathMatches(message, regex, xpath, doc);
81 }
82
83 public static void assertXPathMatches(String regex,
84 String xpath, Document doc)
85 throws XpathException {
86 assertXPathMatches("expected value to match " + regex, regex,
87 xpath, doc);
88 }
89
90 public static void assertXPathMatches(String regex,
91 String xpath, String xml)
92 throws XpathException, SAXException, IOException {
93 assertXPathMatches("expected value to match " + regex, regex,
94 xpath, xml);
95 }
96
97 public static void assertXPathMatches(String regex,
98 String xpath, Reader reader)
99 throws XpathException, SAXException, IOException {
100 assertXPathMatches("expected value to match " + regex, regex,
101 xpath, reader);
102 }
103 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.exceptions;
37
38 /**
39 * Exception thrown when an XML parser-, transformer- or XPath-factory
40 * throws a configuration exception.
41 */
42 public class ConfigurationException extends XMLUnitRuntimeException {
43 public ConfigurationException(Throwable t) {
44 super(t != null ? t.getMessage() : null, t);
45 }
46 public ConfigurationException(String s) {
47 super(s, null);
48 }
49 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.exceptions;
37
38 /**
39 * Base class of any checked exception that can be thrown within
40 * XMLUnit.
41 */
42 public abstract class XMLUnitException extends Exception {
43 private final Throwable cause;
44
45 /**
46 * Inititializes the exeption.
47 *
48 * @param message the detail message
49 * @param cause the root cause of the exception
50 */
51 protected XMLUnitException(String message, Throwable cause) {
52 super(message);
53 this.cause = cause;
54 }
55
56 /**
57 * Root cause of the exception, if any.
58 */
59 public Throwable getCause() {
60 return cause;
61 }
62
63 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.exceptions;
37
38 /**
39 * Base class of any RuntimeException that can be thrown within
40 * XMLUnit.
41 */
42 public class XMLUnitRuntimeException extends RuntimeException {
43 private final Throwable cause;
44
45 /**
46 * Inititializes the exeption.
47 *
48 * @param message the detail message
49 * @param cause the root cause of the exception
50 */
51 public XMLUnitRuntimeException(String message, Throwable cause) {
52 super(message);
53 this.cause = cause;
54 }
55
56 /**
57 * Inititializes an exeption without cause.
58 *
59 * @param message the detail message
60 */
61 public XMLUnitRuntimeException(String message) {
62 this(message, null);
63 }
64
65 /**
66 * Root cause of the exception, if any.
67 */
68 public Throwable getCause() {
69 return cause;
70 }
71
72 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.exceptions;
37
38 /**
39 * Exception an {@link org.custommonkey.xmlunit.XpathEngine
40 * XpathEngine} is allowed to throw.
41 */
42 public class XpathException extends XMLUnitException {
43
44 /**
45 * Inititializes the exeption.
46 *
47 * @param cause the root cause of the exception
48 */
49 public XpathException(Throwable t) {
50 this(t != null ? t.getMessage() : null, t);
51 }
52
53 /**
54 * Inititializes the exeption.
55 *
56 * @param message the detail message
57 * @param cause the root cause of the exception
58 */
59 public XpathException(String message) {
60 this(message, null);
61 }
62
63 /**
64 * Inititializes the exeption.
65 *
66 * @param message the detail message
67 * @param cause the root cause of the exception
68 */
69 public XpathException(String message, Throwable t) {
70 super(message, t);
71 }
72 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import org.custommonkey.xmlunit.NamespaceContext;
39 import org.custommonkey.xmlunit.XMLUnit;
40 import org.custommonkey.xmlunit.XpathEngine;
41 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
42 import org.custommonkey.xmlunit.exceptions.XpathException;
43
44 import javax.xml.xpath.XPath;
45 import javax.xml.xpath.XPathConstants;
46 import javax.xml.xpath.XPathExpressionException;
47 import javax.xml.xpath.XPathFactory;
48
49 import org.w3c.dom.Document;
50 import org.w3c.dom.NodeList;
51
52 /**
53 * XPath engine based on javax.xml.xpath.
54 */
55 public class Jaxp13XpathEngine implements XpathEngine {
56
57 private final XPath xpath;
58
59 public Jaxp13XpathEngine() throws ConfigurationException {
60 try {
61 XPathFactory f = null;
62 if (XMLUnit.getXPathFactory() != null) {
63 f = (XPathFactory) Class.forName(XMLUnit.getXPathFactory())
64 .newInstance();
65 } else {
66 f = XPathFactory.newInstance();
67 }
68
69 xpath = f.newXPath();
70 } catch (Exception ex) {
71 throw new ConfigurationException(ex);
72 }
73 }
74
75 /**
76 * Execute the specified xpath syntax <code>select</code> expression
77 * on the specified document and return the list of nodes (could have
78 * length zero) that match
79 * @param select
80 * @param document
81 * @return list of matching nodes
82 */
83 public NodeList getMatchingNodes(String select, Document document)
84 throws XpathException {
85 try {
86 return (NodeList) xpath.evaluate(select, document,
87 XPathConstants.NODESET);
88 } catch (XPathExpressionException ex) {
89 throw new XpathException(ex);
90 }
91 }
92
93 /**
94 * Evaluate the result of executing the specified xpath syntax
95 * <code>select</code> expression on the specified document
96 * @param select
97 * @param document
98 * @return evaluated result
99 * @throws TransformerException
100 * @throws TransformerConfigurationException
101 */
102 public String evaluate(String select, Document document)
103 throws XpathException {
104 try {
105 return xpath.evaluate(select, document);
106 } catch (XPathExpressionException ex) {
107 throw new XpathException(ex);
108 }
109 }
110
111 public void setNamespaceContext(NamespaceContext ctx) {
112 xpath.setNamespaceContext(new XMLUnitNamespaceContext2Jaxp13(ctx));
113 }
114 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008, 2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import java.util.ArrayList;
39 import java.util.List;
40 import javax.xml.XMLConstants;
41 import javax.xml.transform.Source;
42 import javax.xml.validation.Schema;
43 import javax.xml.validation.SchemaFactory;
44 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
45 import org.xml.sax.ErrorHandler;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
48
49 /**
50 * Validator class based of {@link javax.xml.validation javax.xml.validation}.
51 *
52 * <p>This class provides support for validating schema definitions as
53 * well as instance documents. It defaults to the W3C XML Schema 1.0
54 * but can be used to validate against any schema language supported
55 * by your SchemaFactory implementation.</p>
56 *
57 * <p>An implementation detail of {@code
58 * javax.xml.validation.Validator} leaks into this class: any {@code
59 * xsi:schemaLocation} or {@code xsi:noSchemaLocation} attribute of
60 * the instance document will be ignored if any schema source has been
61 * set. This means you must either specify all sources or none of
62 * them to successfully validate instances.</p>
63 */
64 public class Validator {
65 private final String schemaLanguage;
66 private final SchemaFactory factory;
67 private final ArrayList sources = new ArrayList();
68
69 /**
70 * validates using W3C XML Schema 1.0.
71 */
72 public Validator() {
73 this(XMLConstants.W3C_XML_SCHEMA_NS_URI, null);
74 }
75
76 /**
77 * validates using the specified schema language.
78 *
79 * @param schemaLanguage the schema language to use - see {@link
80 * javax.xml.validation.SchemaFactory SchemaFactory}.
81 */
82 public Validator(String schemaLanguage) {
83 this(schemaLanguage, null);
84 }
85
86 /**
87 * validates using the specified schema factory.
88 */
89 public Validator(SchemaFactory factory) {
90 this(null, factory);
91 }
92
93 /**
94 * validates using the specified schema language or factory.
95 *
96 * @param schemaLanguage the schema language to use - see {@link
97 * javax.xml.validation.SchemaFactory SchemaFactory}.
98 * @param schemaFactory the concrete factory to use. If this is
99 * non-null, the first argument will be ignored.
100 */
101 protected Validator(String schemaLanguage, SchemaFactory factory) {
102 this.schemaLanguage = schemaLanguage;
103 this.factory = factory;
104 }
105
106 /**
107 * Adds a source for the schema defintion.
108 */
109 public void addSchemaSource(Source s) {
110 sources.add(s);
111 }
112
113 /**
114 * Is the given schema definition valid?
115 */
116 public boolean isSchemaValid() {
117 return getSchemaErrors().size() == 0;
118 }
119
120 /**
121 * Obtain a list of all errors in the schema defintion.
122 *
123 * <p>The list contains {@link org.xml.sax.SAXParseException
124 * SAXParseException}s.</p>
125 */
126 public List/*<SAXParseException>*/ getSchemaErrors() {
127 final ArrayList l = new ArrayList();
128 try {
129 parseSchema(new CollectingErrorHandler(l));
130 } catch (SAXException e) {
131 // error should have been recorded in our ErrorHandler, at
132 // least that's what the Javadocs say "SchemaFactory is
133 // not allowed to throw SAXException without first
134 // reporting it to ErrorHandler.".
135 //
136 // Unfortunately not all implementations seem to follow
137 // this rule. In particular using the setup described in
138 // org.custommonkey.xmlunit.jaxp13.test_Validator#XtestGoodRelaxNGCompactSyntaxIsValid()
139 // an exception ("SAXParseException: Content is not
140 // allowed in prolog.") will be thrown that never enters
141 // our Errorhandler.
142 if (l.size() == 0) {
143 l.add(e);
144 }
145 }
146 return l;
147 }
148
149 /**
150 * Is the given schema instance valid according to the configured
151 * schema definition(s)?
152 *
153 * @throws XMLUnitRuntimeException if the schema definition is
154 * invalid or the Source is a SAXSource and the underlying
155 * XMLReader throws an IOException (see {@link
156 * javax.xml.validation.Validator#validate validate in
157 * Validator}).
158 */
159 public boolean isInstanceValid(Source instance)
160 throws XMLUnitRuntimeException {
161 return getInstanceErrors(instance).size() == 0;
162 }
163
164 /**
165 * Obtain a list of all errors in the given instance.
166 *
167 * <p>The list contains {@link org.xml.sax.SAXParseException
168 * SAXParseException}s.</p>
169 *
170 * @throws XMLUnitRuntimeException if the schema definition is
171 * invalid or the Source is a SAXSource and the underlying
172 * XMLReader throws an IOException (see {@link
173 * javax.xml.validation.Validator#validate validate in
174 * Validator}).
175 */
176 public List/*<SAXParseException>*/ getInstanceErrors(Source instance)
177 throws XMLUnitRuntimeException {
178 Schema schema = null;
179 try {
180 schema = parseSchema(null);
181 } catch (SAXException e) {
182 throw new XMLUnitRuntimeException("Schema is invalid", e);
183 }
184
185 final ArrayList l = new ArrayList();
186 javax.xml.validation.Validator v = schema.newValidator();
187 v.setErrorHandler(new CollectingErrorHandler(l));
188 try {
189 v.validate(instance);
190 } catch (SAXException e) {
191 // error should have been recorded in our ErrorHandler,
192 // but better double-check.
193 if (l.size() == 0) {
194 l.add(e);
195 }
196 } catch (java.io.IOException i) {
197 throw new XMLUnitRuntimeException("Error reading instance source",
198 i);
199 }
200 return l;
201 }
202
203 private Schema parseSchema(ErrorHandler h) throws SAXException {
204 SchemaFactory fac = factory != null ? factory
205 : SchemaFactory.newInstance(schemaLanguage);
206 fac.setErrorHandler(h);
207 try {
208 return sources.size() > 0
209 ? fac.newSchema((Source[])
210 sources.toArray(new Source[sources.size()]))
211 : fac.newSchema();
212 } finally {
213 fac.setErrorHandler(null);
214 }
215 }
216
217 private static final class CollectingErrorHandler implements ErrorHandler {
218 private final List l;
219
220 CollectingErrorHandler(List l) {
221 this.l = l;
222 }
223 public void error(SAXParseException e) {
224 l.add(e);
225 }
226 public void fatalError(SAXParseException e) {
227 l.add(e);
228 }
229 public void warning(SAXParseException e) {
230 l.add(e);
231 }
232 }
233 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import org.custommonkey.xmlunit.NamespaceContext;
39
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.Map;
43 import java.util.TreeSet;
44 import javax.xml.XMLConstants;
45
46 /**
47 * Adapts {@link NamespaceContext XMLUnit's NamespaceContext} to
48 * {@link javax.xml.namespace.NamespaceContext JAXP 1.3's
49 * NamespaceContext}.
50 */
51 public class XMLUnitNamespaceContext2Jaxp13
52 implements javax.xml.namespace.NamespaceContext {
53
54 private final Map/*<String, String>*/ nsMap;
55
56 public XMLUnitNamespaceContext2Jaxp13(NamespaceContext ctx) {
57 nsMap = turnIntoMap(ctx);
58 }
59
60 public String getNamespaceURI(String prefix) {
61 if (prefix == null) {
62 throw new IllegalArgumentException("prefix must not be null");
63 }
64 String uri = (String) nsMap.get(prefix);
65 if (uri == null) {
66 uri = XMLConstants.NULL_NS_URI;
67 }
68 return uri;
69 }
70
71 public Iterator getPrefixes(String uri) {
72 if (uri == null) {
73 throw new IllegalArgumentException("uri must not be null");
74 }
75
76 // ensure that the empty string comes out first when asked for
77 // the default namespace URI's prefix
78 TreeSet/*<String>*/ ts = new TreeSet();
79 for (Iterator it = nsMap.entrySet().iterator(); it.hasNext(); ) {
80 Map.Entry/*<String,String>*/ entry = (Map.Entry) it.next();
81 if (uri.equals(entry.getValue())) {
82 ts.add(entry.getKey());
83 }
84 }
85 return ts.iterator();
86 }
87
88 public String getPrefix(String uri) {
89 Iterator i = getPrefixes(uri);
90 return i.hasNext() ? (String) i.next() : null;
91 }
92
93 private static Map turnIntoMap(NamespaceContext ctx) {
94 HashMap/*<String, String>*/ m = new HashMap();
95 for (Iterator i = ctx.getPrefixes(); i.hasNext(); ) {
96 String prefix = (String) i.next();
97 String uri = ctx.getNamespaceURI(prefix);
98 // according to the Javadocs only the constants defined in
99 // XMLConstants are allowed as prefixes for the following
100 // two URIs
101 if (!XMLConstants.XML_NS_URI.equals(uri)
102 && !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri)) {
103 m.put(prefix, uri);
104 }
105 }
106 m.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
107 m.put(XMLConstants.XMLNS_ATTRIBUTE,
108 XMLConstants.XMLNS_ATTRIBUTE_NS_URI);
109 return m;
110 }
111 }
0 <html>
1 <head><title>XMLUnit package documentation</title></head>
2 <body>
3 Contains XMLUnit classes and interfaces.
4 </body>
5 <html>
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.util;
37
38 /**
39 * Simplistic dynamically growing buffer of integers used by DoctypeSupport.
40 *
41 * <p>No attempt has been made to make this class thread-safe at all.
42 * The append methods and indexOf are not too efficient either, but
43 * work for what we need.</p>
44 */
45 public class IntegerBuffer {
46
47 // should be big enough for the DoctypeSupport use case
48 private static final int INITIAL_SIZE = 512;
49
50 private int[] buffer;
51 private int currentSize;
52
53 /**
54 * Creates a new buffer.
55 */
56 public IntegerBuffer() {
57 this(INITIAL_SIZE);
58 }
59
60 /**
61 * Creates a new buffer with the given initial capacity.
62 */
63 public IntegerBuffer(int capacity) {
64 buffer = new int[capacity];
65 }
66
67 /**
68 * Returns the current size.
69 */
70 public int size() {
71 return currentSize;
72 }
73
74 /**
75 * Returns the current capacity (the size the buffer can use
76 * before it needs to grow).
77 */
78 public int capacity() {
79 return buffer.length;
80 }
81
82 /**
83 * Appends a single int.
84 */
85 public void append(int i) {
86 // could simply delegate to the other append methods, but this
87 // (avoiding arraycopy) is more efficient.
88 while (currentSize >= buffer.length) {
89 grow();
90 }
91 buffer[currentSize++] = i;
92 }
93
94 /**
95 * Appends an array of ints.
96 */
97 public void append(int[] i) {
98 // could simply delegate to the other append methods, but this
99 // (avoiding repeated comparisions) is more efficient.
100 while (currentSize + i.length > buffer.length) {
101 grow();
102 }
103 System.arraycopy(i, 0, buffer, currentSize, i.length);
104 currentSize += i.length;
105 }
106
107 /**
108 * Returns an arry view of this buffer's content.
109 */
110 public int[] toIntArray() {
111 int[] i = new int[currentSize];
112 System.arraycopy(buffer, 0, i, 0, currentSize);
113 return i;
114 }
115
116 /**
117 * finds sequence in current buffer.
118 *
119 * @return index of sequence or -1 if not found
120 */
121 public int indexOf(int[] sequence) {
122 int index = -1;
123 for (int i = 0; index == -1 && i <= currentSize - sequence.length;
124 i++) {
125 if (buffer[i] == sequence[0]) {
126 boolean matches = true;
127 for (int j = 1; matches && j < sequence.length; j++) {
128 if (buffer[i + j] != sequence[j]) {
129 matches = false;
130 }
131 }
132 if (matches) {
133 index = i;
134 }
135 }
136 }
137 return index;
138 }
139
140 private void grow() {
141 int[] i = new int[buffer.length * 2 + 1];
142 System.arraycopy(buffer, 0, i, 0, buffer.length);
143 buffer = i;
144 }
145 }
0 <html>
1 <head><title>XMLUnit</title></head>
2 <body>
3 XMLUnit provides extensions to the <a href="http://www.junit.org" target="_none">
4 JUnit</a> framework to allow assertions to be made about XML content.
5 <h3>Using XMLUnit</h3>
6 <ol>
7 <li>Create a subclass of {@link org.custommonkey.xmlunit.XMLTestCase XMLTestCase}
8 something like this:
9 <pre>
10 public class TestSomething extends XMLTestcase {
11 // standard JUnit style constructor
12 public TestSomething(String name) {
13 super(name);
14 }
15 // standard JUnit style method
16 public static TestSuite suite() {
17 return new TestSuite(TestSomething.class);
18 }
19 }
20 </pre>
21 </li>
22 <li>Set the global JAXP settings in {@link org.custommonkey.xmlunit.XMLUnit XMLUnit}
23 so that your chosen parser and transformer are used for the tests.
24 <br /><i>Note:</i>You can skip this bit if you use the default JAXP settings
25 or you have an <a href="http://jakarta.apache.org/ant">Ant task</a> that uses
26 <i>-D</i> JVM options to specify the JAXP settings.
27 <pre>
28 // set the JAXP factories to use the Xerces parser
29 // - declare to throw Exception as if this fails then all the tests will
30 // fail, and JUnit copes with these Exceptions for us
31 public void setUp() throws Exception {
32 XMLUnit.setControlParser(
33 "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
34 // this next line is strictly not required - if no test parser is
35 // explicitly specified then the same factory class will be used for
36 // both test and control
37 XMLUnit.setTestParser(
38 "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
39
40 XMLUnit.setSAXParserFactory(
41 "org.apache.xerces.jaxp.SAXParserFactoryImpl");
42 XMLUnit.setTransformerFactory(
43 "org.apache.xalan.processor.TransformerFactoryImpl");
44 }
45 </pre>
46 </li>
47 <li>Add test methods to make your assertions: the
48 {@link org.custommonkey.xmlunit.XMLTestCase XMLTestCase} javadoc lists the
49 available assertion methods and their usage, but here are some examples...
50 <pre>
51 public void testObjectAsXML() throws Exception {
52 String expectedXML = "....";
53 String objectAsXML = null;
54 //...set up some object here and serialize its state into
55 //our test String...
56 assertXMLEqual(expectedXML, objectAsXML);
57 }
58
59 public void testTransformToFormatB() throws Exception {
60 String expectedFormatB = "....";
61 String formatA = "....";
62 String transformXSLT = "....";
63 Transform formatAToFormatB = new Transform(formatA, transformXSLT);
64 assertXMLEqual(new Diff(expectedFormatB, formatAToFormatB), true);
65 }
66
67 public void testIsValidAfterTransform() throws Exception {
68 String incomingMessage = "....";
69 String toSourceSystemXSLT = "....";
70 Transform transform = new Transform(incomingMessage, toSourceSystemXSLT);
71 assertXMLValid(transform.getResultString());
72 }
73
74 public void testXpaths() throws Exception {
75 String ukCustomerContactPhoneNos = "//customer[@country='UK']/contact/phone";
76 String customerExtract1 = "....";
77 String customerExtract2 = "....";
78 assertXpathsNotEqual(ukCustomerContactPhoneNos, customerExtract1,
79 ukCustomerContactPhoneNos, customerExtract2);
80 }
81
82 public void testXpathValues() throws Exception {
83 String firstListItem = "/html/body/div[@id='myList']/h1/ol/li[1]";
84 String secondListItem = "/html/body/div[@id='myList']/h1/ol/li[2]";
85 String myHtmlPage = "....";
86 assertXpathValuesNotEqual(firstListItem, secondListItem, myHtmlPage);
87 }
88
89 public void testSpecificXpath() throws Exception {
90 String todaysTop10 = "count(//single[@topTen='true'])";
91 String playlist = "....";
92 assertXpathEvaluatesTo("10", todaysTop10, playlist);
93
94 }
95 </pre>
96 </li>
97 </ol>
98
99 <h3>A little bit of history</h3>
100 <p>XMLUnit is the result of the efforts of
101 <a href="mailto:timBacon@primeEight.co.uk">Tim Bacon</a> and
102 <a href="mailto:jeff@custommonkey.org">Jeff Martin</a>. We needed a tool to
103 test the serialization and de-serialiation of objects into XML for an
104 application that sent and received XML messages over HTTP, and this project
105 grew out of that. We hope you find it useful, and welcome any feedback you can
106 give us.</p>
107 </body>
108 </html>
0 <HTML>
1 <HEAD>
2 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
3 <TITLE>Example Code - xmlunit.sourceforge.net</TITLE>
4 </HEAD>
5 <BODY>
6 <PRE>
7 <FONT FACE="Courier" COLOR="#008080">/*
8 ******************************************************************
9 Copyright (c) 2001, Jeff Martin, Tim Bacon
10 All rights reserved.
11 </FONT><FONT FACE="Courier" >
12 </FONT><FONT FACE="Courier" COLOR="#008080">Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions
14 are met:
15 </FONT><FONT FACE="Courier" >
16 </FONT><FONT FACE="Courier" COLOR="#008080"> * Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the following
20 disclaimer in the documentation and/or other materials provided
21 with the distribution.
22 * Neither the name of the xmlunit.sourceforge.net nor the names
23 of its contributors may be used to endorse or promote products
24 derived from this software without specific prior written
25 permission.
26 </FONT><FONT FACE="Courier" >
27 </FONT><FONT FACE="Courier" COLOR="#008080">THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 POSSIBILITY OF SUCH DAMAGE.
39 </FONT><FONT FACE="Courier" >
40 </FONT><FONT FACE="Courier" COLOR="#008080">******************************************************************
41 */
42 </FONT><FONT FACE="Courier" >
43 </FONT><B><FONT FACE="Courier" COLOR="#800080">package</B></FONT><FONT FACE="Courier" > org.custommonkey.xmlunit.examples;
44
45 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > java.io.File;
46 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > java.io.FileReader;
47 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > java.util.List;
48
49 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > javax.xml.transform.stream.StreamSource;
50
51 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > org.w3c.dom.Document;
52 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > org.w3c.dom.Element;
53 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > org.w3c.dom.Node;
54 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > org.w3c.dom.Text;
55
56 </FONT><B><FONT FACE="Courier" COLOR="#800080">import</B></FONT><FONT FACE="Courier" > org.custommonkey.xmlunit.*;
57
58 </FONT><FONT FACE="Courier" COLOR="#008080">/**
59 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">Example</FONT><FONT FACE="Courier" > <a href="index.html">XMLUnit</a> </FONT><FONT FACE="Courier" COLOR="#008080">XMLTestCase</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">code
60 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">Demonstrates</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">use</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">of:</FONT><FONT FACE="Courier" COLOR="#808080">&lt;br /&gt;
61 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;ul&gt;
62 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">XMLTestCase:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXMLEqual(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXMLNotEqual(),
63 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXpathExists(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXpathNotExists(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXpathEvaluatesTo(),
64 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXpathsEqual(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertXpathsNotEqual(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">assertNodeTestPasses()</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
65 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">Diff:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">similar(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">identical()</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
66 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">DetailedDiff:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">getAllDifferences()</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
67 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">DifferenceListener:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">use</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">with</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">Diff</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">class,
68 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">IgnoreTextAndAttributeValuesDifferenceListener</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">implementation</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
69 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">ElementQualifier:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">use</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">with</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">Diff</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">class,
70 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">ElementNameAndTextQualifier</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">implementation</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
71 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">Transform:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">constructors,</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">getResultDocument(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">use</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">with</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">Diff</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">class</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
72 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">Validator:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">constructor,</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">isValid()</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
73 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">TolerantSaxDocumentBuilder</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">and</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">HTMLDocumentBuilder</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">usage</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
74 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">NodeTest:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">CountingNodeTester</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">and</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">custom</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">implementations</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
75 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;li&gt;</FONT><FONT FACE="Courier" COLOR="#008080">XMLUnit</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">static</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">methods:</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">buildDocument(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">buildControlDocument(),
76 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">buildTestDocument(),</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">setIgnoreWhitespace()</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/li&gt;
77 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;/ul&gt;
78 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;br /&gt;</FONT><FONT FACE="Courier" COLOR="#008080">Examples</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">and</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">more</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">at</FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#808080">&lt;a href="http://xmlunit.sourceforge.net"/&gt;</FONT><FONT FACE="Courier" COLOR="#008080">xmlunit.sourceforge.net</FONT><FONT FACE="Courier" COLOR="#808080">&lt;/a&gt;
79 </FONT><FONT FACE="Courier" > </FONT><FONT FACE="Courier" COLOR="#008080">*/
80 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">class</B></FONT><FONT FACE="Courier" > MyXMLTestCase </FONT><B><FONT FACE="Courier" COLOR="#800080">extends</B></FONT><FONT FACE="Courier" > XMLTestCase {
81 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > MyXMLTestCase(String name) {
82 </FONT><B><FONT FACE="Courier" COLOR="#800080">super</B></FONT><FONT FACE="Courier" >(name);
83 }
84 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testForEquality() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
85 String myControlXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;msg&gt;&lt;uuid&gt;0x00435A8C&lt;/uuid&gt;&lt;/msg&gt;"</FONT><FONT FACE="Courier" >;
86 String myTestXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;msg&gt;&lt;localId&gt;2376&lt;/localId&gt;&lt;/msg&gt;"</FONT><FONT FACE="Courier" >;
87 assertXMLEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"comparing test xml to control xml"</FONT><FONT FACE="Courier" >, myControlXML, myTestXML);
88
89 assertXMLNotEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"test xml not similar to control xml"</FONT><FONT FACE="Courier" >, myControlXML, myTestXML);
90 }
91
92 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testIdentical() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
93 String myControlXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;struct&gt;&lt;int&gt;3&lt;/int&gt;&lt;boolean&gt;false&lt;/boolean&gt;&lt;/struct&gt;"</FONT><FONT FACE="Courier" >;
94 String myTestXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;struct&gt;&lt;boolean&gt;false&lt;/boolean&gt;&lt;int&gt;3&lt;/int&gt;&lt;/struct&gt;"</FONT><FONT FACE="Courier" >;
95 Diff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Diff(myControlXML, myTestXML);
96 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"pieces of XML are similar "</FONT><FONT FACE="Courier" > + myDiff, myDiff.similar());
97 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"but are they identical? "</FONT><FONT FACE="Courier" > + myDiff, myDiff.identical());
98 }
99
100 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testAllDifferences() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
101 String myControlXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;news&gt;&lt;item id=\"1\"&gt;War&lt;/item&gt;"
102 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;item id=\"2\"&gt;Plague&lt;/item&gt;&lt;item id=\"3\"&gt;Famine&lt;/item&gt;&lt;/news&gt;"</FONT><FONT FACE="Courier" >;
103 String myTestXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;news&gt;&lt;item id=\"1\"&gt;Peace&lt;/item&gt;"
104 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;item id=\"2\"&gt;Health&lt;/item&gt;&lt;item id=\"3\"&gt;Plenty&lt;/item&gt;&lt;/news&gt;"</FONT><FONT FACE="Courier" >;
105 DetailedDiff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > DetailedDiff(compareXML(myControlXML, myTestXML));
106 List allDifferences = myDiff.getAllDifferences();
107 assertEquals(myDiff.toString(), 0, allDifferences.size());
108 }
109
110 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testCompareToSkeletonXML() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
111 String myControlXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;location&gt;&lt;street-address&gt;22 any street&lt;/street-address&gt;&lt;postcode&gt;XY00 99Z&lt;/postcode&gt;&lt;/location&gt;"</FONT><FONT FACE="Courier" >;
112 String myTestXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;location&gt;&lt;street-address&gt;20 east cheap&lt;/street-address&gt;&lt;postcode&gt;EC3M 1EB&lt;/postcode&gt;&lt;/location&gt;"</FONT><FONT FACE="Courier" >;
113 DifferenceListener myDifferenceListener = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > IgnoreTextAndAttributeValuesDifferenceListener();
114 Diff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Diff(myControlXML, myTestXML);
115 myDiff.overrideDifferenceListener(myDifferenceListener);
116 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"test XML matches control skeleton XML "</FONT><FONT FACE="Courier" > + myDiff, myDiff.similar());
117 }
118
119 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testRepeatedChildElements() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
120 String myControlXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;suite&gt;&lt;test status=\"pass\"&gt;FirstTestCase&lt;/test&gt;&lt;test status=\"pass\"&gt;SecondTestCase&lt;/test&gt;&lt;/suite&gt;"</FONT><FONT FACE="Courier" >;
121 String myTestXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;suite&gt;&lt;test status=\"pass\"&gt;SecondTestCase&lt;/test&gt;&lt;test status=\"pass\"&gt;FirstTestCase&lt;/test&gt;&lt;/suite&gt;"</FONT><FONT FACE="Courier" >;
122
123 assertXMLNotEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"Repeated child elements in different sequence order are not equal by default"</FONT><FONT FACE="Courier" >,
124 myControlXML, myTestXML);
125
126 Diff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Diff(myControlXML, myTestXML);
127 myDiff.overrideElementQualifier(</FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > ElementNameAndTextQualifier());
128 assertXMLEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"But they are equal when an ElementQualifier controls which test element is compared with each control element"</FONT><FONT FACE="Courier" >,
129 myDiff, </FONT><B><FONT FACE="Courier" COLOR="#800080">true</B></FONT><FONT FACE="Courier" >);
130 }
131
132 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testXSLTransformation() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
133 String myInputXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >;
134 File myStylesheetFile = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > File(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >);
135 Transform myTransform = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Transform(myInputXML, myStylesheetFile);
136 String myExpectedOutputXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >;
137 Diff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Diff(myExpectedOutputXML, myTransform);
138 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"XSL transformation worked as expected "</FONT><FONT FACE="Courier" > + myDiff, myDiff.similar());
139 }
140
141 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testAnotherXSLTransformation() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
142 File myInputXMLFile = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > File(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >);
143 File myStylesheetFile = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > File(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >);
144 Transform myTransform = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Transform(</FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > StreamSource(myInputXMLFile), </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > StreamSource(myStylesheetFile));
145 Document myExpectedOutputXML = XMLUnit.buildDocument(XMLUnit.getControlParser(), </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > FileReader(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >));
146 Diff myDiff = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Diff(myExpectedOutputXML, myTransform.getResultDocument());
147 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"XSL transformation worked as expected "</FONT><FONT FACE="Courier" > + myDiff, myDiff.similar());
148 }
149
150 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testValidation() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
151 XMLUnit.getTestDocumentBuilderFactory().setValidating(</FONT><B><FONT FACE="Courier" COLOR="#800080">true</B></FONT><FONT FACE="Courier" >);
152 </FONT><FONT FACE="Courier" COLOR="#008080">// As the document is parsed it is validated against its referenced DTD
153 </FONT><FONT FACE="Courier" > Document myTestDocument = XMLUnit.buildTestDocument(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >);
154 String mySystemId = </FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >;
155 String myDTDUrl = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > File(</FONT><FONT FACE="Courier" COLOR="#0000ff">"..."</FONT><FONT FACE="Courier" >).toURL().toExternalForm();
156 Validator myValidator = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > Validator(myTestDocument, mySystemId, myDTDUrl);
157 assertTrue(</FONT><FONT FACE="Courier" COLOR="#0000ff">"test document validates against unreferenced DTD"</FONT><FONT FACE="Courier" >, myValidator.isValid());
158 }
159
160 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testXPaths() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
161 String mySolarSystemXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;solar-system&gt;&lt;planet name='Earth' position='3' supportsLife='yes'/&gt;"
162 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;planet name='Venus' position='4'/&gt;&lt;/solar-system&gt;"</FONT><FONT FACE="Courier" >;
163 assertXpathExists(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//planet[@name='Earth']"</FONT><FONT FACE="Courier" >, mySolarSystemXML);
164 assertXpathNotExists(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//star[@name='alpha centauri']"</FONT><FONT FACE="Courier" >, mySolarSystemXML);
165 assertXpathsEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//planet[@name='Earth']"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"//planet[@position='3']"</FONT><FONT FACE="Courier" >, mySolarSystemXML);
166 assertXpathsNotEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//planet[@name='Venus']"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"//planet[@supportsLife='yes']"</FONT><FONT FACE="Courier" >, mySolarSystemXML);
167 }
168
169 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testXPathValues() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
170 String myJavaFlavours = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;java-flavours&gt;&lt;jvm current='some platforms'&gt;1.1.x&lt;/jvm&gt;"
171 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;jvm current='no'&gt;1.2.x&lt;/jvm&gt;&lt;jvm current='yes'&gt;1.3.x&lt;/jvm&gt;"
172 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;jvm current='yes' latest='yes'&gt;1.4.x&lt;/jvm&gt;&lt;/java-flavours&gt;"</FONT><FONT FACE="Courier" >;
173 assertXpathEvaluatesTo(</FONT><FONT FACE="Courier" COLOR="#0000ff">"1.4.x"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"//jvm[@latest='yes']"</FONT><FONT FACE="Courier" >, myJavaFlavours);
174 assertXpathEvaluatesTo(</FONT><FONT FACE="Courier" COLOR="#0000ff">"2"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"count(//jvm[@current='yes'])"</FONT><FONT FACE="Courier" >, myJavaFlavours);
175 assertXpathValuesEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//jvm[4]/@latest"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"//jvm[4]/@current"</FONT><FONT FACE="Courier" >, myJavaFlavours);
176 assertXpathValuesNotEqual(</FONT><FONT FACE="Courier" COLOR="#0000ff">"//jvm[2]/@current"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"//jvm[3]/@current"</FONT><FONT FACE="Courier" >, myJavaFlavours);
177 }
178
179 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testXpathsInHTML() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
180 String someBadlyFormedHTML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;html&gt;&lt;title&gt;Ugh&lt;/title&gt;&lt;body&gt;&lt;h1&gt;Heading&lt;ul&gt;&lt;li id='1'&gt;Item One&lt;li id='2'&gt;Item Two"</FONT><FONT FACE="Courier" >;
181 TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > TolerantSaxDocumentBuilder(XMLUnit.getTestParser());
182 HTMLDocumentBuilder htmlDocumentBuilder = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
183 Document wellFormedDocument = htmlDocumentBuilder.parse(someBadlyFormedHTML);
184 assertXpathEvaluatesTo(</FONT><FONT FACE="Courier" COLOR="#0000ff">"Item One"</FONT><FONT FACE="Courier" >, </FONT><FONT FACE="Courier" COLOR="#0000ff">"/html/body//li[@id='1']"</FONT><FONT FACE="Courier" >, wellFormedDocument);
185 }
186
187 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testCountingNodeTester() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
188 String testXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;fibonacci&gt;&lt;val&gt;1&lt;/val&gt;&lt;val&gt;2&lt;/val&gt;&lt;val&gt;3&lt;/val&gt;"
189 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;val&gt;5&lt;/val&gt;&lt;val&gt;9&lt;/val&gt;&lt;/fibonacci&gt;"</FONT><FONT FACE="Courier" >;
190 CountingNodeTester countingNodeTester = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > CountingNodeTester(4);
191 assertNodeTestPasses(testXML, countingNodeTester, Node.TEXT_NODE);
192 }
193
194 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testCustomNodeTester() </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > Exception {
195 String testXML = </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;fibonacci&gt;&lt;val&gt;1&lt;/val&gt;&lt;val&gt;2&lt;/val&gt;&lt;val&gt;3&lt;/val&gt;"
196 </FONT><FONT FACE="Courier" > + </FONT><FONT FACE="Courier" COLOR="#0000ff">"&lt;val&gt;5&lt;/val&gt;&lt;val&gt;9&lt;/val&gt;&lt;/fibonacci&gt;"</FONT><FONT FACE="Courier" >;
197 NodeTest nodeTest = </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > NodeTest(testXML);
198 assertNodeTestPasses(nodeTest, </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > FibonacciNodeTester(),
199 </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">short</B></FONT><FONT FACE="Courier" >[] {Node.TEXT_NODE, Node.ELEMENT_NODE}, </FONT><B><FONT FACE="Courier" COLOR="#800080">true</B></FONT><FONT FACE="Courier" >);
200 }
201
202 </FONT><B><FONT FACE="Courier" COLOR="#800080">private</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">class</B></FONT><FONT FACE="Courier" > FibonacciNodeTester </FONT><B><FONT FACE="Courier" COLOR="#800080">extends</B></FONT><FONT FACE="Courier" > AbstractNodeTester {
203 </FONT><B><FONT FACE="Courier" COLOR="#800080">private</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">int</B></FONT><FONT FACE="Courier" > nextVal = 1, lastVal = 1, priorVal = 0;
204 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testText(Text text) </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > NodeTestException {
205 </FONT><B><FONT FACE="Courier" COLOR="#800080">int</B></FONT><FONT FACE="Courier" > val = Integer.parseInt(text.getData());
206 </FONT><B><FONT FACE="Courier" COLOR="#800080">if</B></FONT><FONT FACE="Courier" > (nextVal != val) {
207 </FONT><B><FONT FACE="Courier" COLOR="#800080">throw</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > NodeTestException(</FONT><FONT FACE="Courier" COLOR="#0000ff">"Incorrect sequence value"</FONT><FONT FACE="Courier" >, text);
208 }
209 nextVal = val + lastVal;
210 priorVal = lastVal;
211 lastVal = val;
212 }
213 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > testElement(Element element) </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > NodeTestException {
214 String name = element.getLocalName();
215 </FONT><B><FONT FACE="Courier" COLOR="#800080">if</B></FONT><FONT FACE="Courier" > (</FONT><FONT FACE="Courier" COLOR="#0000ff">"fibonacci"</FONT><FONT FACE="Courier" >.equals(name) || </FONT><FONT FACE="Courier" COLOR="#0000ff">"val"</FONT><FONT FACE="Courier" >.equals(name)) {
216 </FONT><B><FONT FACE="Courier" COLOR="#800080">return</B></FONT><FONT FACE="Courier" >;
217 }
218 </FONT><B><FONT FACE="Courier" COLOR="#800080">throw</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">new</B></FONT><FONT FACE="Courier" > NodeTestException(</FONT><FONT FACE="Courier" COLOR="#0000ff">"Unexpected element"</FONT><FONT FACE="Courier" >, element);
219 }
220 </FONT><B><FONT FACE="Courier" COLOR="#800080">public</B></FONT><FONT FACE="Courier" > </FONT><B><FONT FACE="Courier" COLOR="#800080">void</B></FONT><FONT FACE="Courier" > noMoreNodes(NodeTest nodeTest) </FONT><B><FONT FACE="Courier" COLOR="#800080">throws</B></FONT><FONT FACE="Courier" > NodeTestException {
221 }
222 }
223 }
224 </FONT><FONT ></FONT></BODY>
225 </PRE>
226 </HTML>
0 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <title>&lt;XmlUnit/&gt;</title>
4 <meta http-equiv="content-type"
5 content="text/html; charset=ISO-8859-1">
6 <meta name="keywords"
7 content="unit testing, test driven development, xml, xmlunit, junit, nunit">
8 <style type="text/css">
9 body{font-family: Helvetica, Arial, sans-serif}
10 code{font-style: italic}
11 </style>
12 </head>
13 <body>
14 <table width="100%" height="100%" border="0">
15 <tbody>
16 <tr>
17 <td colspan="2"><img align="left" src="xmlunit.png"
18 alt="&lt;xml-unit/&gt;" width="331" height="100"> <a href="http://sourceforge.net/projects/xmlunit"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=23187&type=13" width="120" height="30" border="0" alt="Get XML Unit at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a><br>
19 <h1>XMLUnit - JUnit and NUnit testing for XML</h1>
20 </td>
21 </tr>
22 <tr>
23 <td valign="top" colspan="2">
24 <p>For those of you who've got into it you'll know that test
25 driven development is great. It gives you the confidence to change code
26 safe in the knowledge that if something breaks you'll know about it.
27 Except for those bits you don't know how to test. Until now XML has
28 been one of them. Oh sure you can use <code><b>"&lt;stuff&gt;&lt;/stuff&gt;"</b>.equals(<b>"&lt;stuff&gt;&lt;/stuff&gt;"</b>);</code>
29 but is that really gonna work when some joker decides to output a <code><b>&lt;stuff/&gt;</b></code>?
30 -- damned right it's not ;-)</p>
31 <p>XML can be used for just about anything so deciding if two
32 documents are equal to each other isn't as easy as a character for
33 character match. Sometimes</p>
34 <table bgcolor="black">
35 <tbody>
36 <tr>
37 <td bgcolor="white">
38 <pre>&lt;stuff-doc&gt;<br> &lt;stuff&gt;<br> Stuff Stuff Stuff<br> &lt;/stuff&gt;<br> &lt;more-stuff&gt;<br> Some More Stuff<br> &lt;/more-stuff&gt;<br>&lt;/stuff-doc&gt; </pre>
39 </td>
40 <td bgcolor="white">equals</td>
41 <td bgcolor="white">
42 <pre>&lt;stuff-doc&gt;<br> &lt;more-stuff&gt;<br> Some More Stuff&lt;/more-stuff&gt;<br> &lt;stuff&gt;Stuff Stuff Stuff&lt;/stuff&gt;<br>&lt;/stuff-doc&gt; </pre>
43 </td>
44 </tr>
45 </tbody>
46 </table>
47 <p>and sometimes it doesn't... With XMLUnit you get the control,
48 and you get to decide.</p>
49 </td>
50 </tr>
51 <tr>
52 <td>
53 <h2>XMLUnit for Java</h2>
54 </td>
55 <td width="240"> <a href="http://www.junit.org/"><img
56 src="http://www.junit.org/images/junitlogo.gif" alt="JUnit.org"
57 border="0"></a> </td>
58 </tr>
59 <tr>
60 <td colspan="2">
61 <p>The current stable release is XMLUnit 1.5, September 2013.</p>
62 <p>XMLUnit for Java provides two JUnit extension classes, <code>XMLAssert</code>
63 and <code>XMLTestCase</code>,
64 and a set of supporting classes (e.g. <code>Diff</code>, <code>DetailedDiff</code>,<code>Transform</code>,<code>SimpleXpathEngine</code>,<code>Validator</code>,<code>NodeTest</code>)
65 that allow assertions to be made about:</p>
66 <ul>
67 <li>The differences between two pieces of XML</li>
68 <li>The outcome of transforming a piece of XML using XSLT</li>
69 <li>The evaluation of an XPath expression on a piece of XML</li>
70 <li>The validity of a piece of XML</li>
71 <li>Individual nodes in a piece of XML that are exposed by DOM
72 Traversal</li>
73 </ul>
74 <p>XMLUnit for Java can also treat HTML content (even
75 badly-formed HTML) as valid XML to allow these assertions to be made
76 about the content of web pages too.</p>
77 <table border="0" cellspacing="5" cellpadding="5">
78 <tbody>
79 <tr>
80 <td>Read the User's Guide (<a
81 href="userguide/XMLUnit-Java.pdf">PDF</a> or <a
82 href="userguide/html/index.html">HTML</a>)</td>
83 <td><a href="example.html">See some example code</a></td>
84 <td><a href="api/index.html">Browse the Javadocs</a></td>
85 <td><a
86 href="https://sourceforge.net/p/xmlunit/code/HEAD/tree/trunk/">Visit
87 the Subversion repository</a> </td>
88 </tr>
89 </tbody>
90 </table>
91 </td>
92 </tr>
93 <tr>
94 <td>
95 <h2>XMLUnit for .Net</h2>
96 </td>
97 <td width="240"> <a
98 href="http://nunit.org/"><img src="http://nunit.org/img/logo.gif"
99 alt="NUnit.org" border="0"></a> </td>
100 </tr>
101 <tr>
102 <td colspan="2">
103 <p>The current release is <a
104 href="https://sourceforge.net/projects/xmlunit/files/xmlunit%20for%20.Net/XMLUnit%20for%20.NET%200.4/">XmlUnit
105 .Net 0.4</a>, April 2009</p>
106 <p>XMLUnit for .Net provides NUnit extension classes written in
107 C#, e.g. <code>XmlAssertion</code> and <code>XmlDiff</code>, that allow
108 assertions to be made about the differences between two pieces of XML,
109 the validity of a piece of XML, the evaluation of an XPath expression
110 on a piece of XML, and the result of an XSL Transform.<br>
111 </p>
112 <p>Please be aware that the .Net code base is not as advanced as its Java
113 counterpart, in particular there is currently no explicit support for namespaces.</p>
114 </td>
115 </tr>
116 <tr>
117 <td colspan="2">
118 <h2>News</h2>
119 <p> RSS feeds are available for <a
120 href="http://sourceforge.net/export/rss2_projnews.php?group_id=23187&amp;rss_fulltext=1&amp;go"><img
121 src="https://images.sourceforge.net/images/xml.png" border="0"
122 alt="RSS feed">Project news releases</a> and <a
123 href="http://sourceforge.net/export/rss2_projfiles.php?group_id=23187&amp;go"><img
124 src="https://images.sourceforge.net/images/xml.png" border="0"
125 alt="RSS feed">Project file releases</a> .</p>
126 <p> An archive of the project news is available <a
127 href="http://sourceforge.net/news/?group_id=23187">here</a>. </p>
128 </td>
129 </tr>
130 <tr>
131 <td valign="bottom" align="right" colspan="2">
132 <p style="font-size: smaller;">Brought to you by <a
133 href="http://coachspot.blogspot.com/">Tim Bacon</a> and <a
134 href="http://www.custommonkey.org/">Jeff Martin</a></p>
135 </td>
136 </tr>
137 </tbody>
138 </table>
139 </body>
140 </html>
0 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1
2 <html>
3 <head>
4 <title>&lt;xml-unit/&gt;</title>
5 <meta http-equiv="content-type" content=
6 "text/html; charset=ISO-8859-1">
7 <meta name="keywords"
8 content="unit test, test first, xml, testing, framework, junit">
9 <style type="text/css">
10 body{font-family: Helvetica, Arial, sans-serif}
11 code{font-style: italic}
12 </style>
13 </head>
14
15 <body>
16 <table width="100%" height="100%">
17 <tr>
18 <td colspan="2"><img align="left" src="xmlunit.png" alt=
19 "&lt;xml-unit/&gt;" width="331" height="100">
20
21
22 <a href=
23 "http://sourceforge.net"><img align="right" src=
24 "http://sourceforge.net/sflogo.php?group_id=23187" width=
25 "88" height="31" border="0" alt="SourceForge Logo"></a>
26 <h2><a href="http://www.junit.org/">JUnit</a>
27 testing for XML</h2>
28 </td>
29 </tr>
30
31 <tr>
32 <td valign="top">
33
34
35 <p>For those of you who've got into it you'll no that test first
36 coding is great. It gives you the confidence to hack around safe in the
37 knowlegde that if something breaks you'll know about it. Except those bit's you
38 don't know about. Until now XML has been one of them. Oh sure you can use
39 <code><b>"&lt;stuff&gt;&lt;/stuff&gt;"</b>.equals(<b>"&lt;stuff&gt;&lt;/stuff&gt;"</b>);</code> but is that really gonna work when some joker decides to output a <code>&lt;stuff/&gt;</code>, damned right it's not.</p>
40
41 <p>XML can be used for just about anything so deciding if two documents are equal to each other isn't as easy as a character for character match. Somtimes
42 <table bgcolor="black">
43 <tr><td bgcolor="white"><pre>&lt;stuff-doc&gt;
44 &lt;stuff&gt;
45 Stuff Stuff Stuff
46 &lt;/stuff&gt;
47 &lt;more-stuff&gt;
48 Some More Stuff
49 &lt;/more-stuff&gt;
50 &lt;/stuff-doc&gt; </pre>
51 </td><td bgcolor="white">equals</td><td bgcolor="white"><pre>&lt;stuff-doc&gt;
52 &lt;more-stuff&gt;
53 Some More Stuff&lt;/more-stuff&gt;
54 &lt;stuff&gt;Stuff Stuff Stuff&lt;/stuff&gt;
55 &lt;/stuff-doc&gt; </pre></td></tr></table>
56 and sometime it doesn't.</p>
57
58 <p>XMLUnit allows you to <code>assertXMLEquals(<b>"&lt;stuff&gt;&lt;/stuff&gt;"</b>, <b>"&lt;stuff/&gt;"</b>);</code> or and you can do this <code>assertXMLEquals(xmlFile, anotherXmlFile);</code>
59 and this <code>assertXMLEquals(xmlStream, xmlFile);</code></p>
60 <p>The list goes on and on. The Choice is yours.
61 </p>
62 <p>The current release is here -&gt; <a href=
63 "http://sourceforge.net/project/showfiles.php?group_id=23187&amp;release_id=83804">XMLUnit 0.5</a>, 10th April 2002 -
64 <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xmlunit/xmlunit/README?rev=1.2&content-type=text/vnd.viewcvs-markup">Release Notes</a></p>
65
66 <p><a href="doc">Javadocs</a></p>
67 <p><a href="example.html">Example</a></p>
68
69 <p>Browse CVS -&gt; <a href=
70 "http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xmlunit/xmlunit/">
71 CVS</a></p>
72 </td>
73 <td valign="top">
74 <table bgcolor="black" cellspacing="2" width="200">
75 <tr>
76 <td style="font-size: smaller;">
77 <table bgcolor="white" cellspacing="5">
78 <tr><td align="right"><h2>News</h2></td></tr>
79 <tr>
80 <td style="font-size: smaller;">
81 <?php
82 include 'http://sourceforge.net/export/projnews.php?group_id=23187&show_summaries=1&limit=5'
83 ?>
84 </td>
85 </tr>
86 </table>
87 </td>
88 </tr>
89 </table>
90 </td>
91 </tr>
92 <tr>
93 <td valign="bottom" colspan="2">
94 <p style="font-size: smaller;">Brought to you by, <a href="http://www.custommonkey.org/">CustomMonkey.org</a>
95 and <a href="http://www.primeeight.co.uk/">PrimeEight.co.uk</a></p>
96 </td>
97 </tr>
98 </table>
99 </body>
100 </html>
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 <?xml version="1.0" encoding="utf-8"?>
1 <!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.1b1//EN" "http://docbook.org/xml/simple/1.1b1/sdocbook.dtd">
2 <!--
3 Copyright (c) 2001-2014, Jeff Martin, Tim Bacon
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of the xmlunit.sourceforge.net nor the names
17 of its contributors may be used to endorse or promote products
18 derived from this software without specific prior written
19 permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 -->
34
35 <article>
36 <title>XMLUnit Java User's Guide</title>
37 <articleinfo>
38 <authorgroup>
39 <author>
40 <firstname>Tim</firstname>
41 <surname>Bacon</surname>
42 </author>
43 <author>
44 <firstname>Stefan</firstname>
45 <surname>Bodewig</surname>
46 </author>
47 </authorgroup>
48 <revhistory>
49 <revision>
50 <revnumber>1.0</revnumber>
51 <date>January 2003</date>
52 <author>
53 <firstname>Tim</firstname>
54 <surname>Bacon</surname>
55 </author>
56 <revremark>Documentation for XMLUnit Java 1.0</revremark>
57 </revision>
58 <revision>
59 <revnumber>1.1</revnumber>
60 <date>April 2007</date>
61 <revremark>Documentation for XMLUnit Java 1.1</revremark>
62 </revision>
63 <revision>
64 <revnumber>1.2</revnumber>
65 <date>June 2008</date>
66 <revremark>Documentation for XMLUnit Java 1.2</revremark>
67 </revision>
68 <revision>
69 <revnumber>1.3</revnumber>
70 <date>September 2009</date>
71 <revremark>Documentation for XMLUnit Java 1.3</revremark>
72 </revision>
73 <revision>
74 <revnumber>1.4</revnumber>
75 <date>February 2013</date>
76 <revremark>Documentation for XMLUnit Java 1.4</revremark>
77 </revision>
78 <revision>
79 <revnumber>1.5</revnumber>
80 <date>September 2013</date>
81 <revremark>Documentation for XMLUnit Java 1.5</revremark>
82 </revision>
83 <revision>
84 <revnumber>1.6</revnumber>
85 <date>December 2014</date>
86 <revremark>Documentation for XMLUnit Java 1.6</revremark>
87 </revision>
88 </revhistory>
89 </articleinfo>
90
91 <section id="A Tour of XMLUnit"><title>A Tour of XMLUnit</title>
92
93 <para>This first section contains a tour through XMLUnit's
94 features, the next sections will cover them in more detail.</para>
95
96 <para>Note that it has a strong focus on using the
97 <literal>XMLTestCase</literal> class which is one option to use
98 XMLUnit, but not the only one. XMLUnit's features can be fully
99 used without any dependency on JUnit at all.</para>
100
101 <section id="What is XMLUnit?"><title>What is XMLUnit?</title>
102
103 <para>XMLUnit enables JUnit-style assertions to be made about
104 the content and structure of XML<footnote id="more on
105 JUnit"><para>For more information on JUnit see <ulink
106 url="http://www.junit.org">http://www.junit.org</ulink></para></footnote>. It
107 is an open source project hosted at <ulink
108 url="http://xmlunit.sourceforge.net/">http://xmlunit.sourceforge.net/</ulink>
109 that grew out of a need to test a system that generated and
110 received custom XML messages. The problem that we faced was how
111 to verify that the system generated the correct message from a
112 known set of inputs. Obviously we could use a DTD or a schema to
113 validate the message output, but this approach wouldn't allow us
114 to distinguish between valid XML with correct content (e.g.
115 element <literal><![CDATA[<foo>bar</foo>]]></literal>) and valid
116 XML with incorrect content (e.g. element
117 <literal><![CDATA[<foo>baz</foo>]]></literal>). What we really
118 wanted was an <literal>assertXMLEqual()</literal> method, so we
119 could compare the message that we expected the system to
120 generate and the message that the system actually generated. And
121 that was the beginning of XMLUnit.</para>
122 </section>
123 <section id="Quick Tour"><title>Quick tour</title>
124
125 <para>XMLUnit provides a single JUnit extension class,
126 <literal>XMLTestCase</literal>, and a set of supporting classes
127 that allow assertions to be made about:</para>
128
129 <itemizedlist>
130 <listitem>The differences between two pieces of XML (via
131 <literal>Diff</literal> and <literal>DetailedDiff</literal>
132 classes)</listitem>
133
134 <listitem>The validity of a piece of XML (via
135 <literal>Validator</literal> class)</listitem>
136
137 <listitem> The outcome of transforming a piece of XML using
138 XSLT (via <literal>Transform</literal> class)</listitem>
139
140 <listitem>The evaluation of an XPath expression on a piece of
141 XML (via classes implementing the
142 <literal>XpathEngine</literal> interface)</listitem>
143
144 <listitem>Individual nodes in a piece of XML that are exposed
145 by DOM Traversal (via <literal>NodeTest</literal>
146 class)</listitem>
147 </itemizedlist>
148
149 <para>XMLUnit can also treat HTML content, even badly-formed
150 HTML, as valid XML to allow these assertions to be made about
151 web pages (via the <literal>HTMLDocumentBuilder</literal>
152 class).</para>
153 </section>
154
155 <section id="Glossary"><title>Glossary</title>
156
157 <para>As with many projects some words in XMLUnit have
158 particular meanings so here is a quick overview. A
159 <emphasis>piece</emphasis> of XML is a DOM Document, a String
160 containing marked-up content, or a Source or Reader that allows
161 access to marked-up content within some resource. XMLUnit
162 compares the expected <emphasis>control</emphasis> XML to some
163 actual <emphasis>test</emphasis> XML. The comparison can reveal
164 that two pieces of XML are <emphasis>identical</emphasis>,
165 <emphasis>similar</emphasis> or
166 <emphasis>different</emphasis>. The unit of measurement used by
167 the comparison is a <emphasis>difference</emphasis>, and
168 differences can be either <emphasis>recoverable</emphasis> or
169 <emphasis>unrecoverable</emphasis>. Two pieces of XML are
170 <emphasis>identical</emphasis> if there are <emphasis>no
171 differences</emphasis> between them,
172 <emphasis>similar</emphasis> if there are <emphasis>only
173 recoverable differences</emphasis> between them, and
174 <emphasis>different</emphasis> if there are <emphasis>any
175 unrecoverable differences</emphasis> between them.</para>
176 </section>
177
178 <section id="Configuring XMLUnit"><title>Configuring XMLUnit</title>
179
180 <para>There are many Java XML parsers available, and XMLUnit
181 should work with any JAXP compliant parser library, such as
182 Xerces-J <footnote id="xerces-link"><para><ulink
183 url="http://xerces.apache.org/">http://xerces.apache.org/</ulink></para></footnote>
184 from the Apache Software Foundation. To use the XSLT and XPath
185 features of XMLUnit a Trax (the XSLT portion of JAXP) compliant
186 transformation engine is required, such as Xalan-J<footnote
187 id="xalan-link"><para><ulink
188 url="http://xalan.apache.org/">http://xalan.apache.org/</ulink></para></footnote>,
189 from the Apache Software Foundation. To configure XMLUnit to
190 use a specific parser and transformation engine set three System
191 properties before any tests are run, e.g.</para>
192
193 <example><title>Configuring JAXP via System Properties</title>
194 <programlisting language="Java"><![CDATA[
195 System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
196 "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
197 System.setProperty("javax.xml.parsers.SAXParserFactory",
198 "org.apache.xerces.jaxp.SAXParserFactoryImpl");
199 System.setProperty("javax.xml.transform.TransformerFactory",
200 "org.apache.xalan.processor.TransformerFactoryImpl");
201 ]]></programlisting>
202 </example>
203
204 <para>You may want to read <xref linkend="JAXP"/> for more
205 details - in particular if you are using Java 1.4 or
206 later.</para>
207
208 <para>Alternatively there are static methods on the XMLUnit
209 class that can be called directly. The advantage of this
210 approach is that you can specify a different parser class for
211 control and test XML and change the current parser class at any
212 time in your tests, should you need to make assertions about the
213 compatibility of different parsers.</para>
214
215 <example><title>Configuring JAXP via XMLUnit class</title>
216 <programlisting language="Java"><![CDATA[
217 XMLUnit.setControlParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
218 XMLUnit.setTestParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
219 XMLUnit.setSAXParserFactory("org.apache.xerces.jaxp.SAXParserFactoryImpl");
220 XMLUnit.setTransformerFactory("org.apache.xalan.processor.TransformerFactoryImpl");
221 ]]></programlisting>
222 </example>
223
224 </section>
225
226 <section id="Writing XML comparison tests">
227 <title>Writing XML comparison tests</title>
228
229 <para>Let's say we have two pieces of XML that we wish to
230 compare and assert that they are equal. We could write a simple
231 test class like this:</para>
232
233 <example><title>A simple comparison test</title>
234 <programlisting language="Java"><![CDATA[
235 public class MyXMLTestCase extends XMLTestCase {
236 public MyXMLTestCase(String name) {
237 super(name);
238 }
239
240 public void testForEquality() throws Exception {
241 String myControlXML = "<msg><uuid>0x00435A8C</uuid></msg>";
242 String myTestXML = "<msg><localId>2376</localId></msg>";
243 assertXMLEqual("Comparing test xml to control xml",
244 myControlXML, myTestXML);
245 }
246 }]]></programlisting></example>
247
248 <para>The <literal>assertXMLEqual</literal> test will pass if
249 the control and test XML are either similar or
250 identical. Obviously in this case the pieces of XML are
251 different and the test will fail. The failure message indicates
252 both what the difference is and the XPath locations of the nodes
253 that were being compared:</para>
254
255 <programlisting><![CDATA[
256 Comparing test xml to control xml
257 [different] Expected element tag name 'uuid' but was 'localId' - comparing <uuid...> at /msg[1]/uuid[1] to <localId...> at /msg[1]/localId[1]
258 ]]></programlisting>
259
260 <para>When comparing pieces of XML, the
261 <literal>XMLTestCase</literal> actually creates an instance of
262 the <literal>Diff</literal> class. The <literal>Diff</literal>
263 class stores the result of an XML comparison and makes it
264 available through the methods <literal>similar()</literal> and
265 <literal>identical()</literal>. The
266 <literal>assertXMLEqual()</literal> method tests the value of
267 <literal>Diff.similar()</literal> and the
268 <literal>assertXMLIdentical()</literal> method tests the value
269 of <literal>Diff.identical()</literal>.</para>
270
271 <para>It is easy to create a <literal>Diff</literal> instance
272 directly without using the <literal>XMLTestCase</literal> class
273 as below:</para>
274
275 <example><title>Creating a <literal>Diff</literal>
276 instance</title>
277 <programlisting language="Java"><![CDATA[
278 public void testXMLIdentical()throws Exception {
279 String myControlXML =
280 "<struct><int>3</int><boolean>false</boolean></struct>";
281 String myTestXML =
282 "<struct><boolean>false</boolean><int>3</int></struct>";
283 Diff myDiff = new Diff(myControlXML, myTestXML);
284 assertTrue("XML similar " + myDiff.toString(),
285 myDiff.similar());
286 assertTrue("XML identical " + myDiff.toString(),
287 myDiff.identical());
288 }]]></programlisting></example>
289
290 <para>This test fails as two pieces of XML are similar but not
291 identical if their nodes occur in a different sequence. The
292 failure message reported by JUnit from the call to
293 <literal>myDiff.toString()</literal> looks like this:</para>
294
295 <programlisting><![CDATA[
296 [not identical] Expected sequence of child nodes '0' but was '1' - comparing <int...> at /struct[1]/int[1] to <int...> at /struct[1]/int[1]
297 ]]></programlisting>
298
299 <para>For efficiency reasons a <literal>Diff</literal> stops the
300 comparison process as soon as the first difference is found. To
301 get all the differences between two pieces of XML an instance of
302 the <literal>DetailedDiff</literal> class, a subclass of
303 <literal>Diff</literal>, is required. Note that a
304 <literal>DetailedDiff</literal> is constructed using an existing
305 <literal>Diff</literal> instance.</para>
306
307 <para>Consider this test that uses a DetailedDiff:</para>
308
309 <example><title>Using <literal>DetailedDiff</literal></title>
310 <programlisting language="Java"><![CDATA[
311 public void testAllDifferences() throws Exception {
312 String myControlXML = "<news><item id=\"1\">War</item>"
313 + "<item id=\"2\">Plague</item>"
314 + "<item id=\"3\">Famine</item></news>";
315 String myTestXML = "<news><item id=\"1\">Peace</item>"
316 + "<item id=\"2\">Health</item>"
317 + "<item id=\"3\">Plenty</item></news>";
318 DetailedDiff myDiff = new DetailedDiff(new Diff(myControlXML, myTestXML));
319 List allDifferences = myDiff.getAllDifferences();
320 assertEquals(myDiff.toString(), 2, allDifferences.size());
321 }]]></programlisting></example>
322
323 <para>This test fails with the message below as each of the 3
324 news items differs between the control and test XML:</para>
325
326 <programlisting><![CDATA[
327 [different] Expected text value 'War' but was 'Peace' - comparing <item...>War</item> at /news[1]/item[1]/text()[1] to <item...>Peace</item> at /news[1]/item[1]/text()[1]
328 [different] Expected text value 'Plague' but was 'Health' - comparing <item...>Plague</item> at /news[1]/item[2]/text()[1] to <item...>Health</item> at /news[1]/item[2]/text()[1]
329 [different] Expected text value 'Famine' but was 'Plenty' - comparing <item...>Famine</item> at /news[1]/item[3]/text()[1] to <item...>Plenty</item> at /news[1]/item[3]/text()[1]
330 expected <2> but was <3>
331 ]]></programlisting>
332
333 <para>The List returned from the
334 <literal>getAllDifferences()</literal> method contains
335 <literal>Difference</literal> instances. These instances
336 describe both the type<footnote id="DifferenceConstants"><para>A
337 full set of prototype <literal>Difference</literal> instances -
338 one for each type of difference - is defined using final static
339 fields in the <literal>DifferenceConstants</literal>
340 class.</para></footnote> of difference found between a control
341 node and test node and the <literal>NodeDetail</literal> of
342 those nodes (including the XPath location of each
343 node). <literal>Difference</literal> instances are passed at
344 runtime in notification events to a registered
345 <literal>DifferenceListener</literal>, an interface whose
346 default implementation is provided by the
347 <literal>Diff</literal> class.</para>
348
349 <para>However it is possible to override this default behaviour
350 by implementing the interface in your own class. The
351 <literal>IgnoreTextAndAttributeValuesDifferenceListener</literal>
352 class is an example of how to implement a custom
353 <literal>DifferenceListener</literal>. It allows an XML
354 comparison to be made that ignores differences in the values of
355 text and attribute nodes, for example when comparing a skeleton
356 or outline piece of XML to some generated XML.</para>
357
358 <para>The following test illustrates the use of a custom
359 <literal>DifferenceListener</literal>:</para>
360
361 <example><title>Using a custom
362 <literal>DifferenceListener</literal></title>
363 <programlisting language="Java"><![CDATA[
364 public void testCompareToSkeletonXML() throws Exception {
365 String myControlXML = "<location><street-address>22 any street</street-address><postcode>XY00 99Z</postcode></location>";
366 String myTestXML = "<location><street-address>20 east cheap</street-address><postcode>EC3M 1EB</postcode></location>";
367 DifferenceListener myDifferenceListener = new IgnoreTextAndAttributeValuesDifferenceListener();
368 Diff myDiff = new Diff(myControlXML, myTestXML);
369 myDiff.overrideDifferenceListener(myDifferenceListener);
370 assertTrue("test XML matches control skeleton XML",
371 myDiff.similar());
372 }]]></programlisting></example>
373
374 <para>The <literal>DifferenceEngine</literal> class generates
375 the events that are passed to a
376 <literal>DifferenceListener</literal> implementation as two
377 pieces of XML are compared. Using recursion it navigates through
378 the nodes in the control XML DOM, and determines which node in
379 the test XML DOM qualifies for comparison to the current control
380 node. The qualifying test node will match the control node's
381 node type, as well as the node name and namespace (if defined
382 for the control node).</para>
383
384 <para>However when the control node is an
385 <literal>Element</literal>, it is less straightforward to
386 determine which test <literal>Element</literal> qualifies for
387 comparison as the parent node may contain repeated child
388 <literal>Element</literal>s with the same name and namespace. So
389 for <literal>Element</literal> nodes, an instance of the
390 <literal>ElementQualifier</literal> interface is used determine
391 whether a given test <literal>Element</literal> node qualifies
392 for comparison with a control <literal>Element</literal>
393 node. This separates the decision about whether two
394 <literal>Elements</literal> should be compared from the decision
395 about whether those two <literal>Elements</literal> are
396 considered similar. By default an
397 <literal>ElementNameQualifier</literal> class is used that
398 compares the nth child <literal><![CDATA[<abc>]]></literal> test
399 element to the nth child <literal><![CDATA[<abc>]]></literal>
400 control element, i.e. the sequence of the child elements in the
401 test XML is important. However this default behaviour can be
402 overridden using an
403 <literal>ElementNameAndTextQualifier</literal> or
404 <literal>ElementNameAndAttributesQualifier</literal>.</para>
405
406 <para>The test below demonstrates the use of a custom
407 <literal>ElementQualifier</literal>:</para>
408
409 <example><title>Using a custom
410 <literal>ElementQualifier</literal></title>
411 <programlisting language="Java"><![CDATA[
412 public void testRepeatedChildElements() throws Exception {
413 String myControlXML = "<suite>"
414 + "<test status=\"pass\">FirstTestCase</test>"
415 + "<test status=\"pass\">SecondTestCase</test></suite>";
416 String myTestXML = "<suite>"
417 + "<test status=\"pass\">SecondTestCase</test>"
418 + "<test status=\"pass\">FirstTestCase</test></suite>";
419 assertXMLNotEqual("Repeated child elements in different sequence order are not equal by default",
420 myControlXML, myTestXML);
421 Diff myDiff = new Diff(myControlXML, myTestXML);
422 myDiff.overrideElementQualifier(new ElementNameAndTextQualifier());
423 assertXMLEqual("But they are equal when an ElementQualifier controls which test element is compared with each control element",
424 myDiff, true);
425 }]]></programlisting></example>
426
427 <para>Note: calling <literal>toString</literal> on an instance
428 of <literal>Diff</literal> or <literal>DetailedDiff</literal>
429 will perform the comparision and cache its result immediately.
430 If you change the <literal>DifferenceListener</literal> or
431 <literal>ElementQualifier</literal> after calling
432 <literal>toString</literal> it won't have any effect.</para>
433
434 </section>
435
436 <section id="Comparing XML Transformations">
437 <title>Comparing XML Transformations</title>
438
439 <para>XMLUnit can test XSLT transformations at a high level using
440 the <literal>Transform</literal> class that wraps an
441 <literal>javax.xml.transform.Transformer</literal>
442 instance. Knowing the input XML, input stylesheet and expected
443 output XML we can assert that the output of the transformation
444 matches the expected output as follows:</para>
445
446 <example><title>Testing the Result of a Transformation</title>
447 <programlisting language="Java"><![CDATA[
448 public void testXSLTransformation() throws Exception {
449 String myInputXML = "...";
450 File myStylesheetFile = new File("...");
451 Transform myTransform = new Transform(myInputXML, myStylesheetFile);
452 String myExpectedOutputXML = "...";
453 Diff myDiff = new Diff(myExpectedOutputXML, myTransform);
454 assertTrue("XSL transformation worked as expected", myDiff.similar());
455 }]]></programlisting></example>
456
457 <para>The <literal>getResultString()</literal> and
458 <literal>getResultDocument()</literal> methods of the
459 <literal>Transform</literal> class can be used to access the
460 result of the XSLT transformation programmatically if required,
461 for example as below:</para>
462
463 <example><title>Using <literal>Transform</literal>
464 programmatically</title>
465 <programlisting language="Java"><![CDATA[
466 public void testAnotherXSLTransformation() throws Exception {
467 File myInputXMLFile = new File("...");
468 File myStylesheetFile = new File("...");
469 Transform myTransform = new Transform(
470 new StreamSource(myInputXMLFile),
471 new StreamSource(myStylesheetFile));
472 Document myExpectedOutputXML =
473 XMLUnit.buildDocument(XMLUnit.getControlParser(),
474 new FileReader("..."));
475 Diff myDiff = new Diff(myExpectedOutputXML,
476 myTransform.getResultDocument());
477 assertTrue("XSL transformation worked as expected", myDiff.similar());
478 }]]></programlisting></example>
479
480 </section>
481
482 <section id="Validation Tests"><title>Validation Tests</title>
483
484 <para>XML parsers that validate a piece of XML against a DTD are
485 common, however they rely on a DTD reference being present in
486 the XML, and they can only validate against a single DTD. When
487 writing a system that exchanges XML messages with third parties
488 there are times when you would like to validate the XML against
489 a DTD that is not available to the recipient of the message and
490 so cannot be referenced in the message itself. XMLUnit provides
491 a <literal>Validator</literal> class for this purpose.</para>
492
493 <example><title>Validating Against a DTD</title>
494 <programlisting language="Java"><![CDATA[
495 public void testValidation() throws Exception {
496 XMLUnit.getTestDocumentBuilderFactory().setValidating(true);
497 // As the document is parsed it is validated against its referenced DTD
498 Document myTestDocument = XMLUnit.buildTestDocument("...");
499 String mySystemId = "...";
500 String myDTDUrl = new File("...").toURL().toExternalForm();
501 Validator myValidator = new Validator(myTestDocument, mySystemId,
502 myDTDUrl);
503 assertTrue("test document validates against unreferenced DTD",
504 myValidator.isValid());
505 }]]></programlisting></example>
506
507 <para>Starting with XMLUnit 1.1, the
508 <literal>Validator</literal> class can also validate against one
509 or more XML Schema definitions. See <xref
510 linkend="XML Schema Validation"/> for details.</para>
511
512 <para>XMLUnit 1.2 introduces a new <literal>Validator</literal>
513 class that relies on JAXP
514 1.3's <literal>javax.xml.validation</literal> package. This
515 Validator can validate against W3C XML Schema, but may support
516 different Schema languages like RELAX NG if your JAXP
517 implementation supports it. See
518 <xref linkend="JAXP 1.3 Validation"/> for details.</para>
519
520 </section>
521
522 <section id="Xpath Tests"><title>XPath Tests</title>
523
524 <para>One of the strengths of XML is the ability to
525 programmatically extract specific parts of a document using
526 XPath expressions. The <literal>XMLTestCase</literal> class
527 offers a number of XPath related assertion methods, as
528 demonstrated in this test:</para>
529
530 <example><title>Using XPath Tests</title>
531 <programlisting language="Java"><![CDATA[
532 public void testXPaths() throws Exception {
533 String mySolarSystemXML = "<solar-system>"
534 + "<planet name='Earth' position='3' supportsLife='yes'/>"
535 + "<planet name='Venus' position='4'/></solar-system>";
536 assertXpathExists("//planet[@name='Earth']", mySolarSystemXML);
537 assertXpathNotExists("//star[@name='alpha centauri']",
538 mySolarSystemXML);
539 assertXpathsEqual("//planet[@name='Earth']",
540 "//planet[@position='3']", mySolarSystemXML);
541 assertXpathsNotEqual("//planet[@name='Venus']",
542 "//planet[@supportsLife='yes']",
543 mySolarSystemXML);
544 }]]></programlisting></example>
545
546 <para>When an XPath expression is evaluated against a piece of
547 XML a <literal>NodeList</literal> is created that contains the
548 matching <literal>Node</literal>s. The methods in the previous
549 test <literal>assertXpathExists</literal>,
550 <literal>assertXpathNotExists</literal>,
551 <literal>assertXpathsEqual</literal>, and
552 <literal>assertXpathsNotEqual</literal> use these
553 <literal>NodeList</literal>s. However, the contents of a
554 <literal>NodeList</literal> can be flattened (or
555 <literal>String</literal>-ified) to a single value, and XMLUnit
556 also allows assertions to be made about this single value, as in
557 this test<footnote id="XpathEngine note"><para>Each of the
558 <literal>assertXpath...()</literal> methods uses an
559 implementation of the <literal>XpathEngine</literal> interface
560 to evaluate an XPath expression.</para></footnote>:</para>
561
562 <example><title>Testing XPath Values</title>
563 <programlisting language="Java"><![CDATA[
564 public void testXPathValues() throws Exception {
565 String myJavaFlavours = "<java-flavours>"
566 + "<jvm current='some platforms'>1.1.x</jvm>"
567 + "<jvm current='no'>1.2.x</jvm>"
568 + "<jvm current='yes'>1.3.x</jvm>"
569 + "<jvm current='yes' latest='yes'>1.4.x</jvm></javaflavours>";
570 assertXpathEvaluatesTo("2", "count(//jvm[@current='yes'])",
571 myJavaFlavours);
572 assertXpathValuesEqual("//jvm[4]/@latest", "//jvm[4]/@current",
573 myJavaFlavours);
574 assertXpathValuesNotEqual("//jvm[2]/@current",
575 "//jvm[3]/@current", myJavaFlavours);
576 }]]></programlisting></example>
577
578 <para>XPaths are especially useful where a document is made up
579 largely of known, unchanging content with only a small amount of
580 changing content created by the system. One of the main areas
581 where constant "boilerplate" markup is combined with system
582 generated markup is of course in web applications. The power of
583 XPath expressions can make testing web page output quite
584 trivial, and XMLUnit supplies a means of converting even very
585 badly formed HTML into XML to aid this approach to
586 testing.</para>
587
588 <para>The <literal>HTMLDocumentBuilder</literal> class uses the
589 Swing HTML parser to convert marked-up content to Sax
590 events. The <literal>TolerantSaxDocumentBuilder</literal> class
591 handles the Sax events to build up a DOM document in a tolerant
592 fashion i.e. without mandating that opened elements are
593 closed. (In a purely XML world this class would have no purpose
594 as there are plenty of Sax event handlers that can build DOM
595 documents from well formed content). The test below illustrates
596 how the use of these classes:</para>
597
598 <example><title>Working with non well-formed HTML</title>
599 <programlisting language="Java"><![CDATA[
600 public void testXpathsInHTML() throws Exception {
601 String someBadlyFormedHTML = "<html><title>Ugh</title>"
602 + "<body><h1>Heading<ul>"
603 + "<li id='1'>Item One<li id='2'>Item Two";
604 TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder =
605 new TolerantSaxDocumentBuilder(XMLUnit.getTestParser());
606 HTMLDocumentBuilder htmlDocumentBuilder =
607 new HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
608 Document wellFormedDocument =
609 htmlDocumentBuilder.parse(someBadlyFormedHTML);
610 assertXpathEvaluatesTo("Item One", "/html/body//li[@id='1']",
611 wellFormedDocument);
612 }]]></programlisting></example>
613
614 <para>One of the key points about using XPaths with HTML content
615 is that extracting values in tests requires the values to be
616 identifiable. (This is just another way of saying that testing
617 HTML is easier when it is written to be testable.) In the
618 previous example id attributes were used to identify the list
619 item values that needed to be testable, however class attributes
620 or span and div tags can also be used to identify specific
621 content for testing.</para>
622
623 </section>
624
625 <section id="Testing by Tree Walking">
626 <title>Testing by Tree Walking</title>
627
628 <para>The DOM specification allows a <literal>Document</literal>
629 to optionally implement the <literal>DocumentTraversal</literal>
630 interface. This interface allows an application to iterate over
631 the <literal>Node</literal>s contained in a
632 <literal>Document</literal>, or to "walk the DOM tree". The
633 XMLUnit <literal>NodeTest</literal> class and
634 <literal>NodeTester</literal> interface make use of
635 <literal>DocumentTraversal</literal> to expose individual
636 <literal>Node</literal>s in tests: the former handles the
637 mechanics of iteration, and the latter allows custom test
638 strategies to be implemented. A sample test strategy is supplied
639 by the <literal>CountingNodeTester</literal> class that counts
640 the nodes presented to it and compares the actual count to an
641 expected count. The test below illustrates its use:</para>
642
643 <example><title>Using <literal>CountingNodeTester</literal></title>
644 <programlisting language="Java"><![CDATA[
645 public void testCountingNodeTester() throws Exception {
646 String testXML = "<fibonacci><val>1</val><val>2</val><val>3</val>"
647 + "<val>5</val><val>9</val></fibonacci>";
648 CountingNodeTester countingNodeTester = new CountingNodeTester(4);
649 assertNodeTestPasses(testXML, countingNodeTester, Node.TEXT_NODE);
650 }]]></programlisting></example>
651
652 <para>This test fails as there are 5 text nodes, and JUnit
653 supplies the following message:</para>
654
655 <programlisting>
656 Expected node test to pass, but it failed! Counted 5 node(s) but
657 expected 4
658 </programlisting>
659
660 <para>Note that if your DOM implementation does not support the
661 <literal>DocumentTraversal</literal> interface then XMLUnit will
662 throw an <literal>IllegalArgumentException</literal> informing
663 you that you cannot use the <literal>NodeTest</literal> or
664 <literal>NodeTester</literal> classes. Unfortunately even if
665 your DOM implementation does support
666 <literal>DocumentTraversal</literal>, attributes are not exposed
667 by iteration: however they can be examined from the
668 <literal>Element</literal> node that contains them.</para>
669
670 <para>While the previous test could have been easily performed
671 using XPath, there are times when <literal>Node</literal>
672 iteration is more powerful. In general, this is true when there
673 are programmatic relationships between nodes that can be more
674 easily tested iteratively. The following test uses a custom
675 <literal>NodeTester</literal> class to illustrate the
676 potential:</para>
677
678 <example><title>Using a Custom <literal>NodeTester</literal></title>
679 <programlisting language="Java"><![CDATA[
680 public void testCustomNodeTester() throws Exception {
681 String testXML = "<fibonacci><val>1</val><val>2</val><val>3</val>"
682 + "<val>5</val><val>9</val></fibonacci>";
683 NodeTest nodeTest = new NodeTest(testXML);
684 assertNodeTestPasses(nodeTest, new FibonacciNodeTester(),
685 new short[] {Node.TEXT_NODE,
686 Node.ELEMENT_NODE},
687 true);
688 }
689
690 private class FibonacciNodeTester extends AbstractNodeTester {
691 private int nextVal = 1, lastVal = 1, priorVal = 0;
692
693 public void testText(Text text) throws NodeTestException {
694 int val = Integer.parseInt(text.getData());
695 if (nextVal != val) {
696 throw new NodeTestException("Incorrect value", text);
697 }
698 nextVal = val + lastVal;
699 priorVal = lastVal;
700 lastVal = val;
701 }
702
703 public void testElement(Element element) throws NodeTestException {
704 String name = element.getLocalName();
705 if ("fibonacci".equals(name) || "val".equals(name)) {
706 return;
707 }
708 throw new NodeTestException("Unexpected element", element);
709 }
710
711 public void noMoreNodes(NodeTest nodeTest) throws NodeTestException {
712 }
713 }]]></programlisting></example>
714
715 <para>The test fails because the XML contains the wrong value
716 for the last number in the sequence:</para>
717
718 <programlisting>
719 Expected node test to pass, but it failed! Incorrect value [#text: 9]
720 </programlisting>
721
722 </section>
723 </section>
724
725 <section id="Using XMLUnit">
726 <title>Using XMLUnit</title>
727
728 <section id="Requirements">
729 <title>Requirements</title>
730
731 <para>XMLUnit requires a JAXP compliant XML parser virtually
732 everywhere. Several features of XMLUnit also require a JAXP
733 compliant XSLT transformer. If it is available, a JAXP
734 compliant XPath engine will be used for XPath tests.</para>
735
736 <para>To build XMLUnit at least JAXP 1.2 is required, this is
737 the version provided by the Java class library in JDK 1.4. The
738 JAXP 1.3 (i.e. Java5 and above) XPath engine can only be built
739 when JAXP 1.3 is available.</para>
740
741 <para>As long as you don't require support for XML Namespaces or
742 XML Schema, any JAXP 1.1 compliant implementations should work
743 at runtime. For namespace and schema support you will need a
744 parser that complies to JAXP 1.2 and supports the required
745 feature. The XML parser shipping with JDK 1.4 (a version of
746 Apache Crimson) for example is compliant to JAXP 1.2 but doesn't
747 support Schema validation.</para>
748
749 <para>XMLUnit is supposed to build and run on any Java version
750 after 1.3 (at least no new hard JDK 1.4 dependencies have been
751 added in XMLUnit 1.1), but it has only been tested on JDK 1.4.2
752 and above.</para>
753
754 <para>To build XMLUnit JUnit 3.x (only tested with JUnit 3.8.x)
755 is required. It is not required at runtime unless you intend to
756 use the <literal>XMLTestCase</literal> or
757 <literal>XMLAssert</literal> classes.</para>
758 </section>
759
760 <section id="Basic Usage">
761 <title>Basic Usage</title>
762
763 <para>XMLUnit consists of a few classes all living in the
764 <literal>org.custommonkey.xmlunit</literal> package. You can
765 use these classes directly from your code, no matter whether you
766 are writing a unit test or want to use XMLUnit's features for
767 any other purpose.</para>
768
769 <para>This section provides a few hints of where to start if you
770 want to use a certain feature of XMLUnit, more details can be
771 found in the more specific sections later in this
772 document.</para>
773
774 <section id="Basic: Comparing Pieces of XML">
775 <title>Comparing Pieces of XML</title>
776
777 <para>Heart and soul of XMLUnit's comparison engine is
778 <literal>DifferenceEngine</literal> but most of the time you
779 will use it indirectly via the <literal>Diff</literal>
780 class.</para>
781
782 <para>You can influence the engine by providing (custom)
783 implementations for various interfaces and by setting a couple
784 of options on the <literal>XMLUnit</literal> class.</para>
785
786 <para>More information is available in <xref
787 linkend="Comparing Pieces of XML"/>.</para>
788
789 </section>
790
791 <section id="Basic: Validating"><title>Validating</title>
792
793 <para>All validation happens in the
794 <literal>Validator</literal> class. The default is to
795 validate against a DTD, but XML Schema validation can be
796 enabled by an option (see
797 <literal>Validator.useXMLSchema</literal>).</para>
798
799 <para>Several options of the <literal>XMLUnit</literal> class
800 affect validation.</para>
801
802 <para>More information is available in <xref
803 linkend="Validating XML Documents"/>.</para>
804
805 </section>
806
807 <section id="XSLT Transformations"><title>XSLT Transformations</title>
808
809 <para>The <literal>Transform</literal> class provides an easy
810 to use layer on top of JAXP's transformations. An instance of
811 this class is initialized with the source document and a
812 stylesheet and the result of the transformation can be
813 retrieved as a <literal>String</literal> or DOM
814 <literal>Document</literal>.</para>
815
816 <para>The output of <literal>Transform</literal> can be used
817 as input to comparisons, validations, XPath tests and so on.
818 There is no detailed sections on transformations since they
819 are really only a different way to create input for the rest
820 of XMLUnit's machinery. Examples can be found in <xref
821 linkend="Comparing XML Transformations"/>.</para>
822
823 <para>It is possible to provide a custom
824 <literal>javax.xml.transform.URIResolver</literal> via the
825 <literal>XMLUnit.setURIResolver</literal> method.</para>
826
827 <para>You can access the underlying XSLT transformer via
828 <literal>XMLUnit.getTransformerFactory</literal>.</para>
829 </section>
830
831 <section id="XPath Engine">
832 <title>XPath Engine</title>
833
834 <para>The central piece of XMLUnit's XPath support is the
835 <literal>XpathEngine</literal> interface. Currently two
836 implementations of the interface exist,
837 <literal>SimpleXpathEngine</literal> and
838 <literal>org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</literal>.</para>
839
840 <para><literal>SimpleXpathEngine</literal> is a very basic
841 implementation that uses your XSLT transformer under the
842 covers. This also means it will expose you to the bugs found
843 in your transformer like the transformer claiming a stylesheet
844 couldn't be compiled for very basic XPath expressions. This
845 has been reported to be the case for JDK 1.5.</para>
846
847 <para><literal>org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</literal>
848 uses JAXP 1.3's <literal>javax.xml.xpath</literal> package and
849 seems to work more reliable, stable and performant than
850 <literal>SimpleXpathEngine</literal>.</para>
851
852 <para>You use the <literal>XMLUnit.newXpathEngine</literal>
853 method to obtain an instance of the
854 <literal>XpathEngine</literal>. As of XMLUnit 1.1 this will
855 try to use JAXP 1.3 if it is available and fall back to
856 <literal>SimpleXpathEngine</literal>.</para>
857
858 <para>Instances of <literal>XpathEngine</literal> can return
859 the results of XPath queries either as DOM
860 <literal>NodeList</literal> or plain
861 <literal>String</literal>s.</para>
862
863 <para>More information is available in <xref
864 linkend="XPath Tests"/>.</para>
865 </section>
866
867 <section id="Basic: DOM Tree Walking">
868 <title>DOM Tree Walking</title>
869
870 <para>To test pieces of XML by traversing the DOM tree you use
871 the <literal>NodeTester</literal> class. Each DOM
872 <literal>Node</literal> will be passed to a
873 <literal>NodeTester</literal> implementation you provide. The
874 <literal>AbstractNodeTester</literal> class is provided as a
875 NullObject Pattern base class for implementations of your
876 own.</para>
877
878 <para>More information is available in <xref
879 linkend="DOM Tree Walking"/>.</para>
880 </section>
881 </section>
882
883 <section id="Using XMLUnit With JUnit 3.x">
884 <title>Using XMLUnit With JUnit 3.x</title>
885
886 <para>Initially XMLUnit was tightly coupled to JUnit and the
887 recommended approach was to write unit tests by inheriting from
888 the <literal>XMLTestCase</literal> class.
889 <literal>XMLTestCase</literal> provides a pretty long list of
890 <literal>assert...</literal> methods that may simplify your
891 interaction with XMLUnit's internals in many common
892 cases.</para>
893
894 <para>The <literal>XMLAssert</literal> class provides the same
895 set of <literal>assert...</literal>s as static methods. Use
896 <literal>XMLAssert</literal> instead of
897 <literal>XMLTestCase</literal> for your unit tests if you can't
898 or don't want to inherit from
899 <literal>XMLTestCase</literal>.</para>
900
901 <para>All power of XMLUnit is available whether you use
902 <literal>XMLTestCase</literal> and/or
903 <literal>XMLAssert</literal> or the underlying API directly. If
904 you are using JUnit 3.x then using the specific classes may prove
905 to be more convenient.</para>
906
907 </section>
908
909 <section id="Common Configuration Options">
910 <title>Common Configuration Options</title>
911
912 <section id="JAXP">
913 <title>JAXP</title>
914
915 <para>If you are using a JDK 1.4 or later, your Java class
916 library already contains the required XML parsers and XSLT
917 transformers. Still you may want to use a different
918 parser/transformer than the one of your JDK - in particular
919 since the versions shipping with some JDKs are known to
920 contain serious bugs.</para>
921
922 <para>As described in <xref linkend="Configuring XMLUnit"/>
923 there are two main approaches to choose the XML parser of XSLT
924 transformer: System properties and setters in the
925 <literal>XMLUnit</literal> class.</para>
926
927 <para>If you use system properties you have the advantage that
928 your choice affects the whole JAXP system, whether it is used
929 inside of XMLUnit or not. If you are using JDK 1.4 or later
930 you may also want to review the <ulink
931 url="http://java.sun.com/j2se/1.4.2/docs/guide/standards/">Endorsed
932 Standards Override Mechanism</ulink> to use a different
933 parser/transformer than the one shipping with your JDK.</para>
934
935 <para>The second option - using the <literal>XMLUnit</literal>
936 class - allows you to use different parsers for control and
937 test documents, it even allows you to use different parsers
938 for different test cases, if you really want to stretch it
939 that far. It may also work for JDK 1.4 and above, even if you
940 don't override the endorsed standards libraries.</para>
941
942 <para>You can access the underlying JAXP parser by
943 <literal>XMLUnit.newControlParser</literal>,
944 <literal>XMLUnit.newTestParser</literal>,
945 <literal>XMLUnit.getControlDocumentBuilderFactory</literal>,
946 <literal>XMLUnit.getTestDocumentBuilderFactory</literal> and
947 <literal>XMLUnit.getSAXParserFactory</literal> (used by
948 <literal>Validator</literal>). Note that all these methods
949 return factories or parsers that are namespace aware.</para>
950
951 <para>The various <literal>build...</literal> methods in
952 <literal>XMLUnit</literal> provide convenience layers for
953 building DOM <literal>Document</literal>s using the configured
954 parsers.</para>
955
956 <para>You can also set the class name for the
957 <literal>XPathFactory</literal> to use when using JAXP 1.3 by
958 passing the class name to
959 <literal>XMLUnit.setXPathFactory</literal>.</para>
960
961 </section>
962
963 <section id="EntityResolver">
964 <title><literal>EntityResolver</literal></title>
965
966 <para>You can provide a custom
967 <literal>org.xml.sax.EntityResolver</literal> for the control
968 and test parsers via
969 <literal>XMLUnit.setControlEntityResolver</literal> and
970 <literal>XMLUnit.setTestEntityResolver</literal>.
971 <literal>Validator</literal> uses the resolver set via
972 <literal>setControlEntityResolver</literal> as well.</para>
973 </section>
974
975 <section id="Basic: Element Content Whitespace">
976 <title>Element Content Whitespace</title>
977
978 <para>Element content whitespace - also known as ignorable
979 whitespace - is whitespace contained in elements whose content
980 model doesn't allow text content. I.e. the newline and space
981 characters between <literal><![CDATA[<foo>]]></literal> and
982 <literal><![CDATA[<bar>]]></literal> in the following example
983 could belong into this category.</para>
984
985 <programlisting language="XML"><![CDATA[
986 <foo>
987 <bar/></foo>
988 ]]></programlisting>
989
990 <para>Using <literal>XMLUnit.setIgnoreWhitespace</literal> it
991 is possible to make the test and control parser ignore this
992 kind of whitespace.</para>
993
994 <para>Note that setting this property to
995 <literal>true</literal> usually doesn't have any effect since
996 it only works on validating parsers and XMLUnit doesn't enable
997 validation by default. It does have an effect when comparing
998 pieces of XML, though, since the same flag is used for a
999 different purpose as well in that case. See <xref
1000 linkend="Whitespace Handling"/> for more details.</para>
1001
1002 </section>
1003
1004 <section id="XSLT Stylesheet Version">
1005 <title>XSLT Stylesheet Version</title>
1006
1007 <para>Some features of XMLUnit use XSLT stylesheets under the
1008 covers, in particular XSLT will be used to strip element
1009 content whitespace or comments as well as by
1010 <literal>SimpleXpathEngine</literal>. These stylesheets only
1011 require a XSLT transformer that supports XSLT 1.0 and will say
1012 so in the <literal>stylesheet</literal> element.</para>
1013
1014 <para>If your XSLT transformer supports XSLT 2.0 or newer it
1015 may<footnote><para>The W3C recommendation says it
1016 SHOULD.</para></footnote> issue a warning for these stylesheets
1017 which can be annoying. You can use
1018 <literal>XMLUnit.setXSLTVersion</literal> to make XMLUnit
1019 change the version attribute to a different value. Note that
1020 XMLUnit hasn't been tested with a value other than
1021 <literal>"1.0"</literal>.</para>
1022 </section>
1023 </section>
1024
1025 <section id="Providing Input to XMLUnit">
1026 <title>Providing Input to XMLUnit</title>
1027
1028 <para>Most methods in XMLUnit that expect a piece of XML as
1029 input provide several overloads that obtain their input from
1030 different sources. The most common options are:</para>
1031
1032 <itemizedlist>
1033
1034 <listitem>A DOM <literal>Document</literal>.
1035
1036 <para>Here you have all control over the document's
1037 creation. Such a <literal>Document</literal> could as well
1038 be the result of an XSLT transformation via the
1039 <literal>Transform</literal> class.</para>
1040 </listitem>
1041
1042 <listitem>A SAX <literal>InputSource</literal>.
1043
1044 <para>This is the most generic way since
1045 <literal>InputSource</literal> allows you to read from
1046 arbitrary <literal>InputStream</literal>s or
1047 <literal>Reader</literal>s. Use an
1048 <literal>InputStream</literal> wrapped by an
1049 <literal>InputSource</literal> if you want the XML parser to
1050 pick up the proper encoding from the XML declaration.</para>
1051 </listitem>
1052
1053 <listitem>A <literal>String</literal>.
1054
1055 <para>Here a DOM <literal>Document</literal> is built from
1056 the input <literal>String</literal> using the JAXP parser
1057 specified for control or test documents - depending on
1058 whether the input is a control or test piece of XML.</para>
1059
1060 <para>Note that using a <literal>String</literal> assumes
1061 that your XML has already been converted from its XML
1062 encoding to a Java <literal>String</literal> upfront.</para>
1063 </listitem>
1064
1065 <listitem>A <literal>Reader</literal>.
1066
1067 <para>Here a DOM <literal>Document</literal> is built from
1068 the input <literal>Reader</literal> using the JAXP parser
1069 specified for control or test documents - depending on
1070 whether the input is a control or test piece of XML.</para>
1071
1072 <para>Note that using a <literal>Reader</literal> is a
1073 bad choice if your XML encoding is different from your
1074 platform's default encoding since Java's IO system won't
1075 read your XML declaration. It is a good practice to use one
1076 of the other overloads rather than the
1077 <literal>Reader</literal> version to ensure encoding has
1078 been dealt with properly.</para>
1079 </listitem>
1080 </itemizedlist>
1081 </section>
1082
1083 </section>
1084
1085 <section id="Comparing Pieces of XML">
1086 <title>Comparing Pieces of XML</title>
1087
1088 <section id="The Difference Engine">
1089 <title>The Difference Engine</title>
1090
1091 <para>At the center of XMLUnit's support for comparisons is the
1092 <literal>DifferenceEngine</literal> class. In practice you
1093 rarely deal with it directly but rather use it via instances of
1094 <literal>Diff</literal> or <literal>DetailedDiff</literal>
1095 classes (see <xref linkend="Diff"/>).</para>
1096
1097 <para>The <literal>DifferenceEngine</literal> walks two trees of
1098 DOM <literal>Node</literal>s, the control and the test tree, and
1099 compares the nodes. Whenever it detects a difference, it sends
1100 a message to a configured <literal>DifferenceListener</literal>
1101 (see <xref linkend="DifferenceListener"/>) and asks a
1102 <literal>ComparisonController</literal> (see <xref
1103 linkend="ComparisonController"/>) whether the current comparison
1104 should be halted.</para>
1105
1106 <para>In some cases the order of elements in two pieces of XML
1107 may not be significant. If this is true, the
1108 <literal>DifferenceEngine</literal> needs help to determine
1109 which <literal>Element</literal>s to compare. This is the job
1110 of an <literal>ElementQualifier</literal> (see <xref
1111 linkend="ElementQualifier"/>).</para>
1112
1113 <para>The types of differences
1114 <literal>DifferenceEngine</literal> can detect are enumerated in
1115 the <literal>DifferenceConstants</literal> interface and
1116 represented by instances of the <literal>Difference</literal>
1117 class.</para>
1118
1119 <para>A <literal>Difference</literal> can be recoverable;
1120 recoverable <literal>Difference</literal>s make the
1121 <literal>Diff</literal> class consider two pieces of XML similar
1122 while non-recoverable <literal>Difference</literal>s render the
1123 two pieces different.</para>
1124
1125 <para>The types of <literal>Difference</literal>s that are
1126 currently detected are listed in <xref linkend="docleveldiff"/>
1127 to <xref linkend="otherdiff"/> (the first two columns refer to
1128 the <literal>DifferenceConstants</literal> class).</para>
1129
1130 <table frame="all" rules="all" pgwide="1" id="docleveldiff">
1131 <title>Document level <literal>Difference</literal>s detected by
1132 <literal>DifferenceEngine</literal></title>
1133 <tgroup cols="4">
1134 <colspec colname="id" align="center"/>
1135 <colspec colname="constant" align="center"/>
1136 <colspec colname="recoverable" align="center"/>
1137 <colspec colname="description" align="left"/>
1138
1139 <thead>
1140 <row>
1141 <entry><literal>ID</literal></entry>
1142 <entry><literal>Constant</literal></entry>
1143 <entry><literal>recoverable</literal></entry>
1144 <entry align="center">Description</entry>
1145 </row>
1146 </thead>
1147
1148 <tbody>
1149 <row>
1150 <entry><literal>HAS_DOCTYPE_DECLARATION_ID</literal></entry>
1151 <entry><literal>HAS_DOCTYPE_DECLARATION</literal></entry>
1152 <entry><literal>true</literal></entry>
1153 <entry>One piece of XML has a DOCTYPE declaration while
1154 the other one has not.</entry>
1155 </row>
1156 <row>
1157 <entry><literal>DOCTYPE_NAME_ID</literal></entry>
1158 <entry><literal>DOCTYPE_NAME</literal></entry>
1159 <entry><literal>false</literal></entry>
1160 <entry>Both pieces of XML contain a DOCTYPE declaration
1161 but the declarations specify different names for the
1162 root element.</entry>
1163 </row>
1164 <row>
1165 <entry><literal>DOCTYPE_PUBLIC_ID_ID</literal></entry>
1166 <entry><literal>DOCTYPE_PUBLIC_ID</literal></entry>
1167 <entry><literal>false</literal></entry>
1168 <entry>Both pieces of XML contain a DOCTYPE declaration
1169 but the declarations specify different PUBLIC
1170 identifiers.</entry>
1171 </row>
1172 <row>
1173 <entry><literal>DOCTYPE_SYSTEM_ID_ID</literal></entry>
1174 <entry><literal>DOCTYPE_SYSTEM_ID</literal></entry>
1175 <entry><literal>true</literal></entry>
1176 <entry>Both pieces of XML contain a DOCTYPE declaration
1177 but the declarations specify different SYSTEM
1178 identifiers.</entry>
1179 </row>
1180 <row>
1181 <entry><literal>NODE_TYPE_ID</literal></entry>
1182 <entry><literal>NODE_TYPE</literal></entry>
1183 <entry><literal>false</literal></entry>
1184 <entry>The test piece of XML contains a different type
1185 of node than was expected. This type of difference will
1186 also occur if either the root control or test
1187 <literal>Node</literal> is <literal>null</literal> while
1188 the other is not.</entry>
1189 </row>
1190 <row>
1191 <entry><literal>NAMESPACE_PREFIX_ID</literal></entry>
1192 <entry><literal>NAMESPACE_PREFIX</literal></entry>
1193 <entry><literal>true</literal></entry>
1194 <entry>Two nodes use different prefixes for the same
1195 XML Namespace URI in the two pieces of XML.</entry>
1196 </row>
1197 <row>
1198 <entry><literal>NAMESPACE_URI_ID</literal></entry>
1199 <entry><literal>NAMESPACE_URI</literal></entry>
1200 <entry><literal>false</literal></entry>
1201 <entry>Two nodes in the two pieces of XML share the same
1202 local name but use different XML Namespace URIs.</entry>
1203 </row>
1204 <row>
1205 <entry><literal>SCHEMA_LOCATION_ID</literal></entry>
1206 <entry><literal>SCHEMA_LOCATION</literal></entry>
1207 <entry><literal>true</literal></entry>
1208 <entry>Two nodes have different values for the
1209 <literal>schemaLocation</literal> attribute of the
1210 XMLSchema-Instance namespace. The attribute could be
1211 present on only one of the two nodes.</entry>
1212 </row>
1213 <row>
1214 <entry><literal>NO_NAMESPACE_SCHEMA_LOCATION_ID</literal></entry>
1215 <entry><literal>NO_NAMESPACE_SCHEMA_LOCATION</literal></entry>
1216 <entry><literal>true</literal></entry>
1217 <entry>Two nodes have different values for the
1218 <literal>noNamespaceSchemaLocation</literal> attribute
1219 of the XMLSchema-Instance namespace. The attribute
1220 could be present on only one of the two nodes.</entry>
1221 </row>
1222 </tbody>
1223 </tgroup>
1224 </table>
1225
1226 <table frame="all" rules="all" pgwide="1" id="elementleveldiff">
1227 <title>Element level <literal>Difference</literal>s detected by
1228 <literal>DifferenceEngine</literal></title>
1229 <tgroup cols="4">
1230 <colspec colname="id" align="center"/>
1231 <colspec colname="constant" align="center"/>
1232 <colspec colname="recoverable" align="center"/>
1233 <colspec colname="description" align="left"/>
1234
1235 <thead>
1236 <row>
1237 <entry><literal>ID</literal></entry>
1238 <entry><literal>Constant</literal></entry>
1239 <entry><literal>recoverable</literal></entry>
1240 <entry align="center">Description</entry>
1241 </row>
1242 </thead>
1243
1244 <tbody>
1245 <row>
1246 <entry><literal>ELEMENT_TAG_NAME_ID</literal></entry>
1247 <entry><literal>ELEMENT_TAG_NAME</literal></entry>
1248 <entry><literal>false</literal></entry>
1249 <entry>The two pieces of XML contain elements with
1250 different tag names.</entry>
1251 </row>
1252 <row>
1253 <entry><literal>ELEMENT_NUM_ATTRIBUTES_ID</literal></entry>
1254 <entry><literal>ELEMENT_NUM_ATTRIBUTES</literal></entry>
1255 <entry><literal>false</literal></entry>
1256 <entry>The two pieces of XML contain a common element,
1257 but the number of attributes on the element is
1258 different.</entry>
1259 </row>
1260 <row>
1261 <entry><literal>HAS_CHILD_NODES_ID</literal></entry>
1262 <entry><literal>HAS_CHILD_NODES</literal></entry>
1263 <entry><literal>false</literal></entry>
1264 <entry>An element in one piece of XML has child nodes
1265 while the corresponding one in the other has not.</entry>
1266 </row>
1267 <row>
1268 <entry><literal>CHILD_NODELIST_LENGTH_ID</literal></entry>
1269 <entry><literal>CHILD_NODELIST_LENGTH</literal></entry>
1270 <entry><literal>false</literal></entry>
1271 <entry>Two elements in the two pieces of XML differ by
1272 their number of child nodes.</entry>
1273 </row>
1274 <row>
1275 <entry><literal>CHILD_NODELIST_SEQUENCE_ID</literal></entry>
1276 <entry><literal>CHILD_NODELIST_SEQUENCE</literal></entry>
1277 <entry><literal>true</literal></entry>
1278 <entry>Two elements in the two pieces of XML contain the
1279 same child nodes but in a different order.</entry>
1280 </row>
1281 <row>
1282 <entry><literal>CHILD_NODE_NOT_FOUND_ID</literal></entry>
1283 <entry><literal>CHILD_NODE_NOT_FOUND</literal></entry>
1284 <entry><literal>false</literal></entry>
1285 <entry>A child node in one piece of XML couldn't be
1286 matched against any other node of the other piece.</entry>
1287 </row>
1288 <row>
1289 <entry><literal>ATTR_SEQUENCE_ID</literal></entry>
1290 <entry><literal>ATTR_SEQUENCE</literal></entry>
1291 <entry><literal>true</literal></entry>
1292 <entry>The attributes on an element appear in different
1293 order<footnote><para>Note that the order of attributes
1294 is not significant in XML, different parsers may return
1295 attributes in a different order even if parsing the same
1296 XML document. There is an option to turn this check off
1297 - see <xref linkend="Comparing: Configuration"/> - but it is on
1298 by default for backwards compatibility
1299 reasons</para></footnote> in the two pieces of
1300 XML.</entry>
1301 </row>
1302 </tbody>
1303 </tgroup>
1304 </table>
1305
1306 <table frame="all" rules="all" pgwide="1" id="attributeleveldiff">
1307 <title>Attribute level <literal>Difference</literal>s detected by
1308 <literal>DifferenceEngine</literal></title>
1309
1310 <tgroup cols="4">
1311 <colspec colname="id" align="center"/>
1312 <colspec colname="constant" align="center"/>
1313 <colspec colname="recoverable" align="center"/>
1314 <colspec colname="description" align="left"/>
1315
1316 <thead>
1317 <row>
1318 <entry><literal>ID</literal></entry>
1319 <entry><literal>Constant</literal></entry>
1320 <entry><literal>recoverable</literal></entry>
1321 <entry align="center">Description</entry>
1322 </row>
1323 </thead>
1324
1325 <tbody>
1326 <row>
1327 <entry><literal>ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</literal></entry>
1328 <entry><literal>ATTR_VALUE_EXPLICITLY_SPECIFIED</literal></entry>
1329 <entry><literal>true</literal></entry>
1330 <entry>An attribute that has a default value according
1331 to the content model of the element in question has been
1332 specified explicitly in one piece of XML but not in the
1333 other.<footnote><para>In order for this difference to be
1334 detected the parser must have been in validating mode
1335 when the piece of XML was parsed and the DTD or XML
1336 Schema must have been available.</para></footnote></entry>
1337
1338 </row>
1339 <row>
1340 <entry><literal>ATTR_NAME_NOT_FOUND_ID</literal></entry>
1341 <entry><literal>ATTR_NAME_NOT_FOUND</literal></entry>
1342 <entry><literal>false</literal></entry>
1343 <entry>One piece of XML contains an attribute on an
1344 element that is missing in the other.</entry>
1345 </row>
1346 <row>
1347 <entry><literal>ATTR_VALUE_ID</literal></entry>
1348 <entry><literal>ATTR_VALUE</literal></entry>
1349 <entry><literal>false</literal></entry>
1350 <entry>The value of an element's attribute is different
1351 in the two pieces of XML.</entry>
1352 </row>
1353 </tbody>
1354 </tgroup>
1355 </table>
1356
1357 <table frame="all" rules="all" pgwide="1" id="otherdiff">
1358 <title>Other <literal>Difference</literal>s detected by
1359 <literal>DifferenceEngine</literal></title>
1360
1361 <tgroup cols="4">
1362 <colspec colname="id" align="center"/>
1363 <colspec colname="constant" align="center"/>
1364 <colspec colname="recoverable" align="center"/>
1365 <colspec colname="description" align="left"/>
1366
1367 <thead>
1368 <row>
1369 <entry><literal>ID</literal></entry>
1370 <entry><literal>Constant</literal></entry>
1371 <entry><literal>recoverable</literal></entry>
1372 <entry align="center">Description</entry>
1373 </row>
1374 </thead>
1375
1376 <tbody>
1377 <row>
1378 <entry><literal>COMMENT_VALUE_ID</literal></entry>
1379 <entry><literal>COMMENT_VALUE</literal></entry>
1380 <entry><literal>false</literal></entry>
1381 <entry>The content of two comments is different in the
1382 two pieces of XML.</entry>
1383 </row>
1384 <row>
1385 <entry><literal>PROCESSING_INSTRUCTION_TARGET_ID</literal></entry>
1386 <entry><literal>PROCESSING_INSTRUCTION_TARGET</literal></entry>
1387 <entry><literal>false</literal></entry>
1388 <entry>The target of two processing instructions is
1389 different in the two pieces of XML.</entry>
1390 </row>
1391 <row>
1392 <entry><literal>PROCESSING_INSTRUCTION_DATA_ID</literal></entry>
1393 <entry><literal>PROCESSING_INSTRUCTION_DATA</literal></entry>
1394 <entry><literal>false</literal></entry>
1395 <entry>The data of two processing instructions is
1396 different in the two pieces of XML.</entry>
1397 </row>
1398
1399 <row>
1400 <entry><literal>CDATA_VALUE_ID</literal></entry>
1401 <entry><literal>CDATA_VALUE</literal></entry>
1402 <entry><literal>false</literal></entry>
1403 <entry>The content of two CDATA sections is different in
1404 the two pieces of XML.</entry>
1405 </row>
1406 <row>
1407 <entry><literal>TEXT_VALUE_ID</literal></entry>
1408 <entry><literal>TEXT_VALUE</literal></entry>
1409 <entry><literal>false</literal></entry>
1410 <entry>The value of two texts is different in the two
1411 pieces of XML.</entry>
1412 </row>
1413 </tbody>
1414 </tgroup>
1415 </table>
1416
1417 <para>Note that some of the differences listed may be ignored by
1418 the <literal>DifferenceEngine</literal> if certain configuration
1419 options have been specified. See <xref
1420 linkend="Comparing: Configuration"/> for details.</para>
1421
1422 <para><literal>DifferenceEngine</literal> passes differences
1423 found around as instances of the <literal>Difference</literal>
1424 class. In addition to the type of of difference this class also
1425 holds information on the nodes that have been found to be
1426 different. The nodes are described by
1427 <literal>NodeDetail</literal> instances that encapsulate the DOM
1428 <literal>Node</literal> instance as well as the XPath expression
1429 that locates the <literal>Node</literal> inside the given piece
1430 of XML. <literal>NodeDetail</literal> also contains a "value"
1431 that provides more information on the actual values that have
1432 been found to be different, the concrete interpretation depends
1433 on the type of difference as can be seen in <xref
1434 linkend="diffvalue"/>.</para>
1435
1436 <table frame="all" rules="all" pgwide="0" id="diffvalue">
1437 <title>Contents of <literal>NodeDetail.getValue()</literal>
1438 for <literal>Difference</literal>s</title>
1439
1440 <tgroup cols="2">
1441 <colspec colname="id" align="center"/>
1442 <colspec colname="value" align="left"/>
1443
1444 <thead>
1445 <row>
1446 <entry><literal>Difference.getId()</literal></entry>
1447 <entry align="center"><literal>NodeDetail.getValue()</literal></entry>
1448 </row>
1449 </thead>
1450
1451 <tbody>
1452 <row>
1453 <entry><literal>HAS_DOCTYPE_DECLARATION_ID</literal></entry>
1454 <entry><literal>"not null"</literal> if the document has
1455 a DOCTYPE declaration, <literal>"null"</literal>
1456 otherwise.</entry>
1457 </row>
1458 <row>
1459 <entry><literal>DOCTYPE_NAME_ID</literal></entry>
1460 <entry>The name of the root element.</entry>
1461 </row>
1462 <row>
1463 <entry><literal>DOCTYPE_PUBLIC_ID</literal></entry>
1464 <entry>The PUBLIC identifier.</entry>
1465 </row>
1466 <row>
1467 <entry><literal>DOCTYPE_SYSTEM_ID</literal></entry>
1468 <entry>The SYSTEM identifier.</entry>
1469 </row>
1470 <row>
1471 <entry><literal>NODE_TYPE_ID</literal></entry>
1472 <entry>If one node was absent: <literal>"not
1473 null"</literal> if the node exists,
1474 <literal>"null"</literal> otherwise. If the node types
1475 differ the value will be a string-ified version of
1476 <literal>org.w3c.dom.Node.getNodeType()</literal>.</entry>
1477 </row>
1478 <row>
1479 <entry><literal>NAMESPACE_PREFIX_ID</literal></entry>
1480 <entry>The Namespace prefix.</entry>
1481 </row>
1482 <row>
1483 <entry><literal>NAMESPACE_URI_ID</literal></entry>
1484 <entry>The Namespace URI.</entry>
1485 </row>
1486 <row>
1487 <entry><literal>SCHEMA_LOCATION_ID</literal></entry>
1488 <entry>The attribute's value or "[attribute absent]" if
1489 it has not been specified.</entry>
1490 </row>
1491 <row>
1492 <entry><literal>NO_NAMESPACE_SCHEMA_LOCATION_ID</literal></entry>
1493 <entry>The attribute's value or "[attribute absent]" if
1494 it has not been specified.</entry>
1495 </row>
1496 <row>
1497 <entry><literal>ELEMENT_TAG_NAME_ID</literal></entry>
1498 <entry>The tag name with any Namespace information
1499 stripped.</entry>
1500 </row>
1501 <row>
1502 <entry><literal>ELEMENT_NUM_ATTRIBUTES_ID</literal></entry>
1503 <entry>The number of attributes present turned into a
1504 <literal>String</literal>.</entry>
1505 </row>
1506 <row>
1507 <entry><literal>HAS_CHILD_NODES_ID</literal></entry>
1508 <entry><literal>"true"</literal> if the element has
1509 child nodes, <literal>"false"</literal>
1510 otherwise.</entry>
1511 </row>
1512 <row>
1513 <entry><literal>CHILD_NODELIST_LENGTH_ID</literal></entry>
1514 <entry>The number of child nodes present turned into a
1515 <literal>String</literal>.</entry>
1516 </row>
1517 <row>
1518 <entry><literal>CHILD_NODELIST_SEQUENCE_ID</literal></entry>
1519 <entry>The sequence number of this child node turned into a
1520 <literal>String</literal>.</entry>
1521 </row>
1522 <row>
1523 <entry><literal>CHILD_NODE_NOT_FOUND_ID</literal></entry>
1524 <entry>The name of the unmatched node or
1525 <literal>"null"</literal>. If the node is an element
1526 inside an XML namespace the name will be
1527 Java5-<literal>QName</literal>-like
1528 <literal>{NS-URI}LOCAL-NAME</literal> - in all other
1529 cases it is the node's local name.</entry>
1530 </row>
1531 <row>
1532 <entry><literal>ATTR_SEQUENCE_ID</literal></entry>
1533 <entry>The attribute's name.</entry>
1534 </row>
1535 <row>
1536 <entry><literal>ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</literal></entry>
1537 <entry><literal>"true"</literal> if the attribute has
1538 been specified, <literal>"false"</literal>
1539 otherwise.</entry>
1540 </row>
1541 <row>
1542 <entry><literal>ATTR_NAME_NOT_FOUND_ID</literal></entry>
1543 <entry>The attribute's name or
1544 <literal>"null"</literal>. If the attribute belongs to
1545 an XML namespace the name will be
1546 Java5-<literal>QName</literal>-like
1547 <literal>{NS-URI}LOCAL-NAME</literal> - in all other
1548 cases it is the attribute's local name.</entry>
1549 </row>
1550 <row>
1551 <entry><literal>ATTR_VALUE_ID</literal></entry>
1552 <entry>The attribute's value.</entry>
1553 </row>
1554 <row>
1555 <entry><literal>COMMENT_VALUE_ID</literal></entry>
1556 <entry>The actual comment.</entry>
1557 </row>
1558 <row>
1559 <entry><literal>PROCESSING_INSTRUCTION_TARGET_ID</literal></entry>
1560 <entry>The processing instruction's target.</entry>
1561 </row>
1562 <row>
1563 <entry><literal>PROCESSING_INSTRUCTION_DATA_ID</literal></entry>
1564 <entry>The processing instruction's data.</entry>
1565 </row>
1566
1567 <row>
1568 <entry><literal>CDATA_VALUE_ID</literal></entry>
1569 <entry>The content of the CDATA section.</entry>
1570 </row>
1571 <row>
1572 <entry><literal>TEXT_VALUE_ID</literal></entry>
1573 <entry>The actual text.</entry>
1574 </row>
1575 </tbody>
1576 </tgroup>
1577 </table>
1578
1579 <para>As said in the first paragraph you won't deal with
1580 <literal>DifferenceEngine</literal> directly in most cases. In
1581 cases where <literal>Diff</literal> or
1582 <literal>DetailedDiff</literal> don't provide what you need
1583 you'd create an instance of <literal>DifferenceEngine</literal>
1584 passing a <literal>ComparisonController</literal> in the
1585 constructor and invoke <literal>compare</literal> with your DOM
1586 trees to compare as well as a
1587 <literal>DifferenceListener</literal> and
1588 <literal>ElementQualifier</literal>. The listener will be
1589 called on any differences while the <literal>control</literal>
1590 method is executing.</para>
1591
1592 <example>
1593 <title>Using <literal>DifferenceEngine</literal>
1594 Directly</title>
1595 <programlisting language="Java"><![CDATA[
1596 class MyDifferenceListener implements DifferenceListener {
1597 private boolean calledFlag = false;
1598 public boolean called() { return calledFlag; }
1599
1600 public int differenceFound(Difference difference) {
1601 calledFlag = true;
1602 return RETURN_ACCEPT_DIFFERENCE;
1603 }
1604
1605 public void skippedComparison(Node control, Node test) {
1606 }
1607 }
1608
1609 DifferenceEngine engine = new DifferenceEngine(myComparisonController);
1610 MyDifferenceListener listener = new MyDifferenceListener();
1611 engine.compare(controlNode, testNode, listener,
1612 myElementQualifier);
1613 System.err.println("There have been "
1614 + (listener.called() ? "" : "no ")
1615 + "differences.");
1616 ]]></programlisting></example>
1617 </section>
1618
1619 <section id="ComparisonController">
1620 <title><literal>ComparisonController</literal></title>
1621
1622 <para>The <literal>ComparisonController</literal>'s job is to
1623 decide whether a comparison should be halted after a difference
1624 has been found. Its interface is:</para>
1625
1626 <programlisting language="Java"><![CDATA[
1627 /**
1628 * Determine whether a Difference that the listener has been notified of
1629 * should halt further XML comparison. Default behaviour for a Diff
1630 * instance is to halt if the Difference is not recoverable.
1631 * @see Difference#isRecoverable
1632 * @param afterDifference the last Difference passed to <code>differenceFound</code>
1633 * @return true to halt further comparison, false otherwise
1634 */
1635 boolean haltComparison(Difference afterDifference);
1636 ]]></programlisting>
1637
1638 <para>Whenever a difference has been detected by the
1639 <literal>DifferenceEngine</literal> the
1640 <literal>haltComparison</literal> method will be called
1641 immediately after the <literal>DifferenceListener</literal> has
1642 been informed of the difference. This is true no matter what
1643 type of <literal>Difference</literal> has been found or which
1644 value the <literal>DifferenceListener</literal> has
1645 returned.</para>
1646
1647 <para>The only implementations of
1648 <literal>ComparisonController</literal> that ship with XMLUnit
1649 are <literal>Diff</literal> and <literal>DetailedDiff</literal>,
1650 see <xref linkend="Diff"/> for details about them.</para>
1651
1652 <para>A <literal>ComparisonController</literal> that halted the
1653 comparison on any non-recoverable difference could be
1654 implemented as:</para>
1655
1656 <example>
1657 <title>A Simple
1658 <literal>ComparisonController</literal></title>
1659 <programlisting language="Java"><![CDATA[
1660 public class HaltOnNonRecoverable implements ComparisonController {
1661 public boolean haltComparison(Difference afterDifference) {
1662 return !afterDifference.isRecoverable();
1663 }
1664 }
1665 ]]></programlisting></example>
1666 </section>
1667
1668 <section id="DifferenceListener">
1669 <title><literal>DifferenceListener</literal></title>
1670
1671 <para><literal>DifferenceListener</literal> contains two
1672 callback methods that are invoked by the
1673 <literal>DifferenceEngine</literal> when differences are
1674 detected:</para>
1675
1676 <programlisting language="Java"><![CDATA[
1677 /**
1678 * Receive notification that 2 nodes are different.
1679 * @param difference a Difference instance as defined in {@link
1680 * DifferenceConstants DifferenceConstants} describing the cause
1681 * of the difference and containing the detail of the nodes that
1682 * differ
1683 * @return int one of the RETURN_... constants describing how this
1684 * difference was interpreted
1685 */
1686 int differenceFound(Difference difference);
1687
1688 /**
1689 * Receive notification that a comparison between 2 nodes has been skipped
1690 * because the node types are not comparable by the DifferenceEngine
1691 * @param control the control node being compared
1692 * @param test the test node being compared
1693 * @see DifferenceEngine
1694 */
1695 void skippedComparison(Node control, Node test);
1696 ]]></programlisting>
1697
1698 <para><literal>differenceFound</literal> is invoked by
1699 <literal>DifferenceEngine</literal> as soon as a difference has
1700 been detected. The return value of that method is completely
1701 ignored by <literal>DifferenceEngine</literal>, it becomes
1702 important when used together with <literal>Diff</literal>,
1703 though (see <xref linkend="Diff"/>). The return value should be
1704 one of the four constants defined in the the
1705 <literal>DifferenceListener</literal> interface:</para>
1706
1707 <programlisting language="Java"><![CDATA[
1708 /**
1709 * Standard return value for the <code>differenceFound</code> method.
1710 * Indicates that the <code>Difference</code> is interpreted as defined
1711 * in {@link DifferenceConstants DifferenceConstants}.
1712 */
1713 int RETURN_ACCEPT_DIFFERENCE;
1714 /**
1715 * Override return value for the <code>differenceFound</code> method.
1716 * Indicates that the nodes identified as being different should be
1717 * interpreted as being identical.
1718 */
1719 int RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
1720 /**
1721 * Override return value for the <code>differenceFound</code> method.
1722 * Indicates that the nodes identified as being different should be
1723 * interpreted as being similar.
1724 */
1725 int RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
1726 /**
1727 * Override return value for the <code>differenceFound</code> method.
1728 * Indicates that the nodes identified as being similar should be
1729 * interpreted as being different.
1730 */
1731 int RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT = 3;
1732 ]]></programlisting>
1733
1734 <para>The <literal>skippedComparison</literal> method is
1735 invoked if the <literal>DifferenceEngine</literal> encounters
1736 two <literal>Node</literal>s it cannot compare. Before invoking
1737 <literal>skippedComparison</literal>
1738 <literal>DifferenceEngine</literal> will have invoked
1739 <literal>differenceFound</literal> with a
1740 <literal>Difference</literal> of type
1741 <literal>NODE_TYPE</literal>.</para>
1742
1743 <para>A custom <literal>DifferenceListener</literal> that
1744 ignored any DOCTYPE related differences could be written
1745 as:</para>
1746
1747 <example>
1748 <title>A <literal>DifferenceListener</literal> that Ignores
1749 DOCTYPE Differences</title>
1750 <programlisting language="Java"><![CDATA[
1751 public class IgnoreDoctype implements DifferenceListener {
1752 private static final int[] IGNORE = new int[] {
1753 DifferenceConstants.HAS_DOCTYPE_DECLARATION_ID,
1754 DifferenceConstants.DOCTYPE_NAME_ID,
1755 DifferenceConstants.DOCTYPE_PUBLIC_ID_ID,
1756 DifferenceConstants.DOCTYPE_SYSTEM_ID_ID
1757 };
1758
1759 static {
1760 Arrays.sort(IGNORE);
1761 }
1762
1763 public int differenceFound(Difference difference) {
1764 return Arrays.binarySearch(IGNORE, difference.getId()) >= 0
1765 ? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
1766 : RETURN_ACCEPT_DIFFERENCE;
1767 }
1768
1769 public void skippedComparison(Node control, Node test) {
1770 }
1771 }
1772 ]]></programlisting></example>
1773
1774 <para>Apart from <literal>Diff</literal> and
1775 <literal>DetailedDiff</literal> XMLUnit ships with an additional
1776 implementation of <literal>DifferenceListener</literal>.</para>
1777
1778 <section id="IgnoreTextAndAttributeValuesDifferenceListener">
1779 <title><literal>IgnoreTextAndAttributeValuesDifferenceListener</literal></title>
1780
1781 <para><literal>IgnoreTextAndAttributeValuesDifferenceListener</literal>
1782 doesn't do anything in <literal>skippedComparison</literal>.
1783 It "downgrades" <literal>Difference</literal>s of type
1784 <literal>ATTR_VALUE</literal>,
1785 <literal>ATTR_VALUE_EXPLICITLY_SPECIFIED</literal> and
1786 <literal>TEXT_VALUE</literal> to recoverable
1787 differences.</para>
1788
1789 <para>This means if instances of
1790 <literal>IgnoreTextAndAttributeValuesDifferenceListener</literal>
1791 are used together with <literal>Diff</literal> then two pieces
1792 of XML will be considered similar if they have the same basic
1793 structure. They are not considered identical, though.</para>
1794
1795 <para>Note that the list of ignored differences doesn't cover
1796 all textual differences. You should configure XMLUnit to
1797 ignore comments and whitespace and to consider CDATA sections
1798 and text nodes to be the same (see <xref
1799 linkend="Comparing: Configuration"/>) in order to cover
1800 <literal>COMMENT_VALUE</literal> and
1801 <literal>CDATA_VALUE</literal> as well.</para>
1802
1803 </section>
1804 </section>
1805
1806 <section id="ElementQualifier">
1807 <title><literal>ElementQualifier</literal></title>
1808
1809 <para>When <literal>DifferenceEngine</literal> encounters a list
1810 of DOM <literal>Element</literal>s as children of another
1811 <literal>Element</literal> it will ask the configured
1812 <literal>ElementQualifier</literal> which
1813 <literal>Element</literal> of the control piece of XML should be
1814 compared to which of the test piece. Its contract is:</para>
1815
1816 <programlisting language="Java"><![CDATA[
1817 /**
1818 * Determine whether two elements are comparable
1819 * @param control an Element from the control XML NodeList
1820 * @param test an Element from the test XML NodeList
1821 * @return true if the elements are comparable, false otherwise
1822 */
1823 boolean qualifyForComparison(Element control, Element test);
1824 ]]></programlisting>
1825
1826 <para>For any given <literal>Element</literal> in the control
1827 piece of XML <literal>DifferenceEngine</literal> will cycle
1828 through the corresponding list of <literal>Element</literal>s in
1829 the test piece of XML until
1830 <literal>qualifyForComparison</literal> has returned
1831 <literal>true</literal> or the test document is
1832 exhausted.</para>
1833
1834 <para>When using <literal>DifferenceEngine</literal> or
1835 <literal>Diff</literal> it is completely legal to set the
1836 <literal>ElementQualifier</literal> to <literal>null</literal>.
1837 In this case any kind of <literal>Node</literal> is compared to
1838 the test <literal>Node</literal> that appears at the same
1839 position in the sequence.</para>
1840
1841 <example id="eq-nodelist-example">
1842 <title>Example Nodes for <literal>ElementQualifier</literal>
1843 (the comments are not part of the example)</title>
1844 <programlisting language="XML"><![CDATA[
1845 <!-- control piece of XML -->
1846 <parent>
1847 <child1/> <!-- control node 1 -->
1848 <child2/> <!-- control node 2 -->
1849 <child2 foo="bar">xyzzy</child2> <!-- control node 3 -->
1850 <child2 foo="baz"/> <!-- control node 4 -->
1851 </parent>
1852
1853 <!-- test piece of XML -->
1854 <parent>
1855 <child2 foo="baz"/> <!-- test node 1 -->
1856 <child1/> <!-- test node 2 -->
1857 <child2>xyzzy</child2> <!-- test node 3 -->
1858 <child2 foo="bar"/> <!-- test node 4 -->
1859 </parent>
1860 ]]></programlisting></example>
1861
1862 <para>Taking <xref linkend="eq-nodelist-example"/> without any
1863 <literal>ElementQualifier</literal>
1864 <literal>DifferenceEngine</literal> will compare control node
1865 <literal>n</literal> to test node <literal>n</literal> for
1866 <literal>n</literal> between 1 and 4. In many cases this is
1867 exactly what is desired, but sometimes
1868 <literal><![CDATA[<a><b/><c/></a>]]></literal> should be similar
1869 to <literal><![CDATA[<a><c/><b/></a>]]></literal> because the
1870 order of elements doesn't matter - this is when you'd use a
1871 different <literal>ElementQualifier</literal>. XMLUnit ships
1872 with several implementations.</para>
1873
1874 <section id="ElementNameQualifier">
1875 <title><literal>ElementNameQualifier</literal></title>
1876
1877 <para>Only <literal>Element</literal>s with the same name -
1878 and Namespace URI if present - qualify.</para>
1879
1880 <para>In <xref linkend="eq-nodelist-example"/> this means
1881 control node 1 will be compared to test node 2. Then control
1882 node 2 will be compared to test node 3 because
1883 <literal>DifferenceEngine</literal> will start to search for
1884 the matching test <literal>Element</literal> at the second
1885 test node, the same sequence number the control node is at.
1886 Control node 3 is compared to test node 3 as well and control
1887 node 4 to test node 4.</para>
1888 </section>
1889
1890 <section id="ElementNameAndAttributeQualifier">
1891 <title><literal>ElementNameAndAttributeQualifier</literal></title>
1892
1893 <para>Only <literal>Element</literal>s with the same name -
1894 and Namespace URI if present - as well as the same values for
1895 all attributes given in
1896 <literal>ElementNameAndAttributeQualifier</literal>'s
1897 constructor qualify.</para>
1898
1899 <para>Let's say <literal>"foo"</literal> has been passed to
1900 <literal>ElementNameAndAttributeQualifier</literal>'s
1901 constructor when looking at <xref
1902 linkend="eq-nodelist-example"/>. This again means control
1903 node 1 will be compared to test node 2 since they do have the
1904 same name and no value at all for attribute
1905 <literal>"foo"</literal>. Then control node 2 will be
1906 compared to test node 3 - again, no value for
1907 <literal>"foo"</literal>. Control node 3 is compared to test
1908 node 4 as they have the same value <literal>"bar"</literal>.
1909 Finally control node 4 is compared to test node 1; here
1910 <literal>DifferenceEngine</literal> searches from the
1911 beginning of the test node list after test node 4 didn't
1912 match.</para>
1913
1914 <para>There are three constructors in
1915 <literal>ElementNameAndAttributeQualifier</literal>. The
1916 no-arg constructor creates an instance that compares all
1917 attributes while the others will compare a single attribute or
1918 a given subset of all attributes.</para>
1919 </section>
1920
1921 <section id="ElementNameAndTextQualifier">
1922 <title><literal>ElementNameAndTextQualifier</literal></title>
1923
1924 <para>Only <literal>Element</literal>s with the same name -
1925 and Namespace URI if present - as well as the same text
1926 content nested into them qualify.</para>
1927
1928 <para>In <xref linkend="eq-nodelist-example"/> this means
1929 control node 1 will be compared to test node 2 since they both
1930 don't have any nested text at all. Then control node 2 will
1931 be compared to test node 4. Control node 3 is compared to
1932 test node 3 since they have the same nested text and control
1933 node 4 to test node 4.</para>
1934 </section>
1935
1936 <section id="RecursiveElementNameAndTextQualifier">
1937 <title><literal>org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</literal></title>
1938
1939 <para>All <literal>ElementQualifier</literal>s seen so far
1940 only looked at the <literal>Element</literal>s themselves and
1941 not at the structure nested into them at a deeper level. A
1942 frequent user question has been which
1943 <literal>ElementQualifier</literal> should be used if the
1944 pieces of XML in <xref linkend="htmltable"/> should be
1945 considered similar.</para>
1946
1947 <example id="htmltable">
1948 <title>Example for
1949 <literal>RecursiveElementNameAndTextQualifier</literal>
1950 (the comments are not part of the example)</title>
1951 <programlisting language="HTML"><![CDATA[
1952 <!-- control -->
1953 <table>
1954 <tr> <!-- control row 1 -->
1955 <td>foo</td>
1956 </tr>
1957 <tr> <!-- control row 2 -->
1958 <td>bar</td>
1959 </tr>
1960 </table>
1961
1962 <!-- test -->
1963 <table>
1964 <tr> <!-- test row 1 -->
1965 <td>bar</td>
1966 </tr>
1967 <tr> <!-- test row 2 -->
1968 <td>foo</td>
1969 </tr>
1970 </table>
1971 ]]></programlisting></example>
1972
1973 <para>At first glance
1974 <literal>ElementNameAndTextQualifier</literal> should work but
1975 it doesn't. When <literal>DifferenceEngine</literal>
1976 processed the children of <literal>table</literal> it would
1977 compare control row 1 to test row 1 since both
1978 <literal>tr</literal> elements have the same name and both
1979 have no textual content at all.</para>
1980
1981 <para>What is needed in this case is an
1982 <literal>ElementQualifier</literal> that looks at the element's
1983 name, as well as the name of the first child element and the
1984 text nested into that first child element. This is what
1985 <literal>RecursiveElementNameAndTextQualifier</literal>
1986 does.</para>
1987
1988 <para><literal>RecursiveElementNameAndTextQualifier</literal>
1989 ignores whitespace between the elements leading up to the
1990 nested text.</para>
1991 </section>
1992
1993 <section id="MultiLevelElementNameAndTextQualifier">
1994 <title><literal>org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier</literal></title>
1995
1996 <para>
1997 <literal>MultiLevelElementNameAndTextQualifier</literal> has
1998 in a way been the predecessor
1999 of <xref linkend="RecursiveElementNameAndTextQualifier"><literal>RecursiveElementNameAndTextQualifier</literal></xref>.
2000 It also matches element names and those of nested child
2001 elements until it finds matches, but
2002 unlike <literal>RecursiveElementNameAndTextQualifier</literal>,
2003 you must
2004 tell <literal>MultiLevelElementNameAndTextQualifier</literal>
2005 at which nesting level it should expect the nested text.
2006 </para>
2007
2008 <para>
2009 <literal>MultiLevelElementNameAndTextQualifier</literal>'s
2010 constructor expects a single argument which is the nesting
2011 level of the expected text. If you use an argument of 1,
2012 <literal>MultiLevelElementNameAndTextQualifier</literal> is
2013 identical to <literal>ElementNameAndTextQualifier</literal>.
2014 In <xref linkend="htmltable"/> a value of 2 would be
2015 needed.</para>
2016
2017 <para>By default
2018 <literal>MultiLevelElementNameAndTextQualifier</literal>
2019 will not ignore whitespace between the elements leading up
2020 to the nested text. If your piece of XML contains this sort
2021 of whitespace (like <xref linkend="htmltable"/> which
2022 contains a newline and several space characters between
2023 <literal>&lt;tr&gt;</literal> and
2024 <literal>&lt;td&gt;</literal>) you can either instruct
2025 XMLUnit to ignore whitespace completely (see
2026 <xref linkend="Whitespace Handling"/>) or use the two-arg
2027 constructor of
2028 <literal>MultiLevelElementNameAndTextQualifier</literal>
2029 introduced with XMLUnit 1.2 and set the
2030 <literal>ignoreEmptyTexts</literal> argument to
2031 true.</para>
2032
2033 <para>In
2034 general <literal>RecursiveElementNameAndTextQualifier</literal>
2035 requires less knowledge upfront and its whitespace-handling
2036 is more intuitive.</para>
2037 </section>
2038
2039 </section>
2040
2041 <section id="Diff">
2042 <title><literal>Diff</literal> and
2043 <literal>DetailedDiff</literal></title>
2044
2045 <para><literal>Diff</literal> and
2046 <literal>DetailedDiff</literal> provide simplified access to
2047 <literal>DifferenceEngine</literal> by implementing the
2048 <literal>ComparisonController</literal> and
2049 <literal>DifferenceListener</literal> interfaces themselves.
2050 They cover the two most common use cases for comparing two
2051 pieces of XML: checking whether the pieces are different (this
2052 is what <literal>Diff</literal> does) and finding all
2053 differences between them (this is what
2054 <literal>DetailedDiff</literal> does).</para>
2055
2056 <para><literal>DetailedDiff</literal> is a subclass of
2057 <literal>Diff</literal> and can only be constructed by creating
2058 a <literal>Diff</literal> instance first.</para>
2059
2060 <para>The major difference between them is their implementation
2061 of the <literal>ComparisonController</literal> interface:
2062 <literal>DetailedDiff</literal> will never stop the comparison
2063 since it wants to collect all differences.
2064 <literal>Diff</literal> in turn will halt the comparison as soon
2065 as the first <literal>Difference</literal> is found that is not
2066 recoverable. In addition <literal>DetailedDiff</literal>
2067 collects all <literal>Difference</literal>s in a list and
2068 provides access to it.</para>
2069
2070 <para>By default <literal>Diff</literal> will consider two
2071 pieces of XML as identical if no differences have been found at
2072 all, similar if all differences that have been found have been
2073 recoverable (see <xref linkend="docleveldiff"/> to <xref
2074 linkend="otherdiff"/>) and different as soon as any
2075 non-recoverable difference has been found.</para>
2076
2077 <para>It is possible to specify a
2078 <literal>DifferenceListener</literal> to <literal>Diff</literal>
2079 using the <literal>overrideDifferenceListener</literal> method.
2080 In this case each <literal>Difference</literal> will be
2081 evaluated by the passed in
2082 <literal>DifferenceListener</literal>. By returning
2083 <literal>RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL</literal> the
2084 custom listener can make <literal>Diff</literal> ignore the
2085 difference completely. Likewise any
2086 <literal>Difference</literal> for which the custom listener
2087 returns
2088 <literal>RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR</literal> will
2089 be treated as if the <literal>Difference</literal> was
2090 recoverable.</para>
2091
2092 <para>There are several overloads of the <literal>Diff</literal>
2093 constructor that allow you to specify your piece of XML in many
2094 ways. There are overloads that accept additional
2095 <literal>DifferenceEngine</literal> and
2096 <literal>ElementQualifier</literal> arguments. Passing in a
2097 <literal>DifferenceEngine</literal> of your own is the only way
2098 to use a <literal>ComparisonController</literal> other than
2099 <literal>Diff</literal>.</para>
2100
2101 <para>Note that <literal>Diff</literal> and
2102 <literal>DetailedDiff</literal> use
2103 <literal>ElementNameQualifier</literal> as their default
2104 <literal>ElementQualifier</literal>. This is different from
2105 <literal>DifferenceEngine</literal> which defaults to no
2106 <literal>ElementQualifier</literal> at all.</para>
2107
2108 <para>To use a custom <literal>ElementQualifier</literal> you
2109 can also use the <literal>overrideElementQualifier</literal>
2110 method. Use this with an argument of <literal>null</literal> to
2111 unset the default <literal>ElementQualifier</literal> as
2112 well.</para>
2113
2114 <para>To compare two pieces of XML you'd create a
2115 <literal>Diff</literal> instance from those two pieces and
2116 invoke <literal>identical</literal> to check that there have
2117 been no differences at all and <literal>similar</literal> to
2118 check that any difference, if any, has been recoverable. If the
2119 pieces are identical they are also similar. Likewise if they
2120 are not similar they can't be identical either.</para>
2121
2122 <example>
2123 <title>Comparing Two Pieces of XML Using
2124 <literal>Diff</literal></title>
2125 <programlisting language="Java"><![CDATA[
2126 Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
2127 assertFalse(d.identical()); // CHILD_NODELIST_SEQUENCE Difference
2128 assertTrue(d.similar());
2129 ]]></programlisting></example>
2130
2131 <para>The result of the comparison is cached in
2132 <literal>Diff</literal>, repeated invocations of
2133 <literal>identical</literal> or <literal>similar</literal> will
2134 not reevaluate the pieces of XML.</para>
2135
2136 <para>Note: calling <literal>toString</literal> on an instance
2137 of <literal>Diff</literal> or <literal>DetailedDiff</literal>
2138 will perform the comparision and cache its result immediately.
2139 If you change the <literal>DifferenceListener</literal> or
2140 <literal>ElementQualifier</literal> after calling
2141 <literal>toString</literal> it won't have any effect.</para>
2142
2143 <para><literal>DetailedDiff</literal> provides only a single
2144 constructor that expects a <literal>Diff</literal> as argument.
2145 Don't use <literal>DetailedDiff</literal> if all you need to
2146 know is whether two pieces of XML are identical/similar - use
2147 <literal>Diff</literal> directly since its short-cut
2148 <literal>ComparisonController</literal> implementation will save
2149 time in this case.</para>
2150
2151 <example>
2152 <title>Finding All Differences Using
2153 <literal>DetailedDiff</literal></title>
2154 <programlisting language="Java"><![CDATA[
2155 Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
2156 DetailedDiff dd = new DetailedDiff(d);
2157 dd.overrideElementQualifier(null);
2158 assertFalse(dd.similar());
2159 List l = dd.getAllDifferences();
2160 assertEquals(2, l.size()); // expected <b/> but was <c/> and vice versa
2161 ]]></programlisting></example>
2162
2163 </section>
2164
2165 <section id="MatchTracker">
2166 <title><literal>MatchTracker</literal></title>
2167
2168 <para>Sometimes you might be interested in any sort of
2169 comparison result and want to get notified of successful matches
2170 as well. Maybe you want to provide feedback on the amount of
2171 differences and similarities between two documents, for
2172 example.</para>
2173
2174 <para>The interface <literal>MatchTracker</literal> can be
2175 implemented to get notified on each and every successful match,
2176 note that there may be a lot more comparisons going on than you
2177 might expect and that your callback gets notified a lot.</para>
2178
2179 <example>
2180 <title>The <literal>MatchTracker</literal> interface</title>
2181 <programlisting language="Java"><![CDATA[
2182 package org.custommonkey.xmlunit;
2183
2184 /**
2185 * Listener for callbacks from a {@link DifferenceEngine#compare
2186 * DifferenceEngine comparison} that is notified on each and every
2187 * comparision that resulted in a match.
2188 */
2189 public interface MatchTracker {
2190 /**
2191 * Receive notification that 2 match.
2192 * @param match a Difference instance as defined in {@link
2193 * DifferenceConstants DifferenceConstants} describing the test
2194 * that matched and containing the detail of the nodes that have
2195 * been compared
2196 */
2197 void matchFound(Difference difference);
2198 }
2199 ]]></programlisting></example>
2200
2201 <para>Despite its name the <literal>Difference</literal>
2202 instance passed into the <literal>matchFound</literal> method
2203 really describes a match and not a difference. You can expect
2204 that the <literal>getValue</literal> method on both the
2205 control and the test <literal>NodeDetail</literal> will be
2206 equal.</para>
2207
2208 <para><literal>DifferenceEngine</literal> provides a constructor
2209 overload that allows you to pass in
2210 a <literal>MatchTracker</literal> instance and also provides
2211 a <literal>setMatchTracker</literal>
2212 method. <literal>Diff</literal>
2213 and <literal>DetailedDiff</literal>
2214 provide <literal>overrideMatchTracker</literal> methods that
2215 fill the same purpose.</para>
2216
2217 <para>Note that your <literal>MatchTracker</literal> won't
2218 receive any callbacks once the
2219 configured <literal>ComparisonController</literal> has decided
2220 that <literal>DifferenceEngine</literal> should halt the
2221 comparison.</para>
2222
2223 </section>
2224
2225 <section id="Comparing: JUnit 3">
2226 <title>JUnit 3.x Convenience Methods</title>
2227
2228 <para><literal>XMLAssert</literal> and
2229 <literal>XMLTestCase</literal> contain quite a few overloads of
2230 methods for comparing two pieces of XML.</para>
2231
2232 <para>The method's names use the word <literal>Equal</literal>
2233 to mean the same as <literal>similar</literal> in the
2234 <literal>Diff</literal> class (or throughout this guide). So
2235 <literal>assertXMLEqual</literal> will assert that only
2236 recoverable differences have been encountered where
2237 <literal>assertXMLNotEqual</literal> asserts that some
2238 differences have been non-recoverable.
2239 <literal>assertXMLIdentical</literal> asserts that there haven't
2240 been any differences at all while
2241 <literal>assertXMLNotIdentical</literal> asserts that there have
2242 been differences (recoverable or not).</para>
2243
2244 <para>Most of the overloads of <literal>assertXMLEqual</literal>
2245 just provide different means to specify the pieces of XML as
2246 <literal>String</literal>s, <literal>InputSource</literal>s,
2247 <literal>Reader</literal>s<footnote><para>See <xref
2248 linkend="Providing Input to XMLUnit"/> for some advice on choosing your input
2249 format.</para></footnote> or <literal>Document</literal>s. For each
2250 method there is a version that takes an additional
2251 <literal>err</literal> argument which is used to create the
2252 message if the assertion fails.</para>
2253
2254 <para>If you don't need any control over the
2255 <literal>ElementQualifier</literal> or
2256 <literal>DifferenceListener</literal> used by
2257 <literal>Diff</literal> these methods will save some boilerplate
2258 code. If <literal>CONTROL</literal> and <literal>TEST</literal>
2259 are pieces of XML represented as one of the supported inputs
2260 then</para>
2261
2262 <programlisting language="Java"><![CDATA[
2263 Diff d = new Diff(CONTROL, TEST);
2264 assertTrue("expected pieces to be similar, " + d.toString(),
2265 d.similar());
2266 ]]></programlisting>
2267
2268 <para>and</para>
2269
2270 <programlisting language="Java"><![CDATA[
2271 assertXMLEqual("expected pieces to be similar", CONTROL, TEST);
2272 ]]></programlisting>
2273
2274 <para>are equivalent.</para>
2275
2276 <para>If you need more control over the <literal>Diff</literal>
2277 instance there is a version of <literal>assertXMLEqual</literal>
2278 (and <literal>assertXMLIdentical</literal>) that accepts a
2279 <literal>Diff</literal> instance as its argument as well as a
2280 <literal>boolean</literal> indicating whether you expect the
2281 <literal>Diff</literal> to be <literal>similar</literal>
2282 (<literal>identical</literal>) or not.</para>
2283
2284 <para><literal>XMLTestCase</literal> contains a couple of
2285 <literal>compareXML</literal> methods that really are only
2286 shortcuts to <literal>Diff</literal>'s constructors.</para>
2287
2288 <para>There is no way to use <literal>DifferenceEngine</literal>
2289 or <literal>DetailedDiff</literal> directly via the convenience
2290 methods.</para>
2291
2292 </section>
2293
2294 <section id="Comparing: Configuration">
2295 <title>Configuration Options</title>
2296
2297 <para>Unless you are using <literal>Document</literal> or
2298 <literal>DOMSource</literal> overrides when specifying your
2299 pieces of XML, XMLUnit will use the configured XML parsers (see
2300 <xref linkend="JAXP"/>) and <literal>EntityResolver</literal>s
2301 (see <xref linkend="EntityResolver"/>). There are configuration
2302 options to use different settings for the control and test
2303 pieces of XML.</para>
2304
2305 <para>In addition some of the other configuration settings may
2306 lead to XMLUnit using the configured XSLT transformer (see <xref
2307 linkend="JAXP"/>) under the covers.</para>
2308
2309 <section id="Whitespace Handling">
2310 <title>Whitespace Handling</title>
2311
2312 <para>Two different configuration options affect how XMLUnit
2313 treats whitespace in comparisons:</para>
2314
2315 <itemizedlist>
2316
2317 <listitem>Element Content Whitespace (see <xref
2318 linkend="Basic: Element Content Whitespace"/>)
2319
2320 <para>If XMLUnit has been configured to ignore element
2321 content whitespace it will trim any text nodes found by
2322 the parser. This means that there won't appear to be any
2323 textual content in element <literal>&lt;foo&gt;</literal>
2324 for the following example. If you don't set
2325 <literal>XMLUnit.setIgnoreWhitespace</literal> there would
2326 be textual content consisting of a new line
2327 character.</para>
2328
2329 <programlisting language="XML"><![CDATA[
2330 <foo>
2331 </foo>
2332 ]]></programlisting>
2333
2334 <para>At the same time the following two
2335 <literal>&lt;foo&gt;</literal> elements will be considered
2336 identical if the option has been enabled, though.</para>
2337
2338 <programlisting language="XML"><![CDATA[
2339 <foo>bar</foo>
2340 <foo> bar </foo>
2341 ]]></programlisting>
2342
2343 <para>When this option is set to <literal>true</literal>,
2344 <literal>Diff</literal> will use the XSLT transformer
2345 under the covers.</para>
2346 </listitem>
2347
2348 <listitem>"Normalizing" Whitespace
2349
2350 <para>If you set
2351 <literal>XMLUnit.setNormalizeWhitespace</literal> to true
2352 then XMLUnit will replace any kind of whitespace found in
2353 character content with a SPACE character and collapse
2354 consecutive whitespace characters to a single SPACE. It
2355 will also trim the resulting character content on both
2356 ends.</para>
2357
2358 <para>The following two <literal>&lt;foo&gt;</literal>
2359 elements will be considered identical if the option has
2360 been set:</para>
2361
2362 <programlisting language="XML"><![CDATA[
2363 <foo>bar baz</foo>
2364 <foo> bar
2365 baz</foo>
2366 ]]></programlisting>
2367
2368 <para>Note that this is not related to "normalizing" the
2369 document as a whole (see <xref
2370 linkend="Normalizing Documents"/>).</para>
2371
2372 </listitem>
2373
2374 </itemizedlist>
2375 </section>
2376
2377 <section id="Normalizing Documents">
2378 <title>"Normalizing" <literal>Document</literal>s</title>
2379
2380 <para>"Normalize" in this context corresponds to the
2381 <literal>normalize</literal> method in DOM's
2382 <literal>Document</literal> class. It is the process of
2383 merging adjacent <literal>Text</literal> nodes and is not
2384 related to "normalizing whitespace" as described in the
2385 previous section.</para>
2386
2387 <para>Usually you don't need to care about this option since
2388 the XML parser is required to normalize the
2389 <literal>Document</literal> when creating it. The only reason
2390 you may want to change the option via
2391 <literal>XMLUnit.setNormalize</literal> is that your
2392 <literal>Document</literal> instances have not been created by
2393 an XML parser but rather been put together in memory using the
2394 DOM API directly.</para>
2395 </section>
2396
2397 <section id="Ignoring Comments">
2398 <title>Ignoring Comments</title>
2399
2400 <para>Using <literal>XMLUnit.setIgnoreComments</literal> you
2401 can make XMLUnit's difference engine ignore comments
2402 completely.</para>
2403
2404 <para>When this option is set to <literal>true</literal>,
2405 <literal>Diff</literal> will use the XSLT transformer under
2406 the covers.</para>
2407 </section>
2408
2409 <section id="Treating CDATA Sections and Text Nodes Alike">
2410 <title>Treating CDATA Sections and Text Nodes Alike</title>
2411
2412 <para>It is not always necessary to know whether a text has
2413 been put into a CDATA section or not. Using
2414 <literal>XMLUnit.setIgnoreDiffBetweenTextAndCDATA</literal>
2415 you can make XMLUnit consider the following two pieces of XML
2416 identical:</para>
2417
2418 <programlisting language="XML"><![CDATA[
2419 <foo>&lt;bar&gt;</foo>
2420 ]]></programlisting>
2421 <programlisting language="XML">
2422 &lt;foo>&lt;![CDATA[&lt;bar&gt;]]&gt;&lt;/foo>
2423 </programlisting>
2424 </section>
2425
2426 <section id="Entity Reference Expansion">
2427 <title>Entity Reference Expansion</title>
2428
2429 <para>Normally the XML parser will expand character references
2430 to their Unicode equivalents but for more complex entity
2431 definitions the parser may expand them or not.
2432 Using <literal>XMLUnit.setExpandEntityReferences</literal> you
2433 can control the parser's setting.</para>
2434
2435 </section>
2436
2437 <section id="Comparison of Unmatched Elements">
2438 <title>Comparison of Unmatched Elements</title>
2439
2440 <para>When XMLUnit cannot match a control Element to a test
2441 Element (the configured ElementQualifier - see
2442 <xref linkend="ElementQualifier"/> - doesn't return true for
2443 any of the test Elements) it will try to compare it against
2444 the first unmatched test Element (if there is one).
2445 Starting with XMLUnit 1.3 one can
2446 use <literal>XMLUnit.setCompareUnmatched</literal> to
2447 disable this behavior and
2448 generate <literal>CHILD_NODE_NOT_FOUND</literal> differences
2449 instead.</para>
2450
2451 <para>If the control document is
2452 <programlisting language="XML"><![CDATA[
2453 <root>
2454 <a/>
2455 </root>
2456 ]]></programlisting>
2457 and the test document is
2458 <programlisting language="XML"><![CDATA[
2459 <root>
2460 <b/>
2461 </root>
2462 ]]></programlisting>
2463
2464 the default setting will create a
2465 single <literal>ELEMENT_TAG_NAME</literal> Difference
2466 ("expected a but found b").
2467 Setting <literal>XMLUnit.setCompareUnmatched</literal> to
2468 false will create two Differences of
2469 type <literal>CHILD_NODE_NOT_FOUND</literal> (one for "a" and
2470 one for "b") instead.</para>
2471 </section>
2472
2473 </section>
2474 </section>
2475
2476 <section id="Validating XML Documents">
2477 <title>Validating XML Documents</title>
2478
2479 <section id="The Validator Class">
2480 <title>The <literal>Validator</literal> Class</title>
2481
2482 <para>The <literal>Validator</literal> class encapsulates
2483 XMLUnit's validation support. It will use the
2484 <literal>SAXParser</literal> configured in XMLUnit (see <xref
2485 linkend="JAXP"/>).</para>
2486
2487 <para>The piece of XML to validate is specified in the
2488 constructor. The constructors using more than a single argument
2489 are only relevant if you want to validate against a DTD and need
2490 to provide the location of the DTD itself - for details see the
2491 next section.</para>
2492
2493 <para>By default, <literal>Validator</literal> will validate
2494 against a DTD, but it is possible to validate against a (or
2495 multiple) Schema(s) as well. Schema validation requires an XML
2496 parser that supports it, of course.</para>
2497
2498 <section id="DTD Validation">
2499 <title>DTD Validation</title>
2500 </section>
2501
2502 <para>Validating against a DTD is straight forward if the piece
2503 of XML contains a <literal>DOCTYPE</literal> declaration with a
2504 <literal>SYSTEM</literal> identifier that can be resolved at
2505 validation time. Simply create a <literal>Validator</literal>
2506 object using one of the single argument constructors.</para>
2507
2508 <example>
2509 <title>Validating Against the DTD Defined in
2510 <literal>DOCTYPE</literal></title>
2511 <programlisting language="Java"><![CDATA[
2512 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
2513 Validator v = new Validator(is);
2514 boolean isValid = v.isValid();
2515 ]]></programlisting></example>
2516
2517 <para>If the piece of XML doesn't contain any
2518 <literal>DOCTYPE</literal> declaration at all or it contains a
2519 <literal>DOCTYPE</literal> but you want to validate against a
2520 different DTD, you'd use one of the three argument versions of
2521 <literal>Validator</literal>'s constructors. In this case the
2522 <literal>publicId</literal> argument becomes the
2523 <literal>PUBLIC</literal> and <literal>systemId</literal> the
2524 <literal>SYSTEM</literal> identifier of the
2525 <literal>DOCTYPE</literal> that is implicitly added to the piece
2526 of XML. Any existing <literal>DOCTYPE</literal> will be
2527 removed. The <literal>systemId</literal> should be a URL that
2528 can be resolved by your parser.</para>
2529
2530 <example>
2531 <title>Validating a Piece of XML that doesn't Contain a
2532 <literal>DOCTYPE</literal></title>
2533 <programlisting language="Java"><![CDATA[
2534 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
2535 Validator v = new Validator(is,
2536 (new File(myDTD)).toURI().toURL().toString(),
2537 myPublicId);
2538 boolean isValid = v.isValid();
2539 ]]></programlisting></example>
2540
2541 <para>If the piece of XML already has the correct
2542 <literal>DOCTYPE</literal> declaration but the declaration
2543 either doesn't specify a <literal>SYSTEM</literal> identifier at
2544 all or you want the <literal>SYSTEM</literal> identifier to
2545 resolve to a different location you have two options:</para>
2546
2547 <itemizedlist>
2548 <listitem>Use one of the two argument constructors and specify
2549 the alternative URL as
2550 <literal>systemId</literal>.
2551
2552 <example>
2553 <title>Validating Against a Local DTD</title>
2554 <programlisting language="Java"><![CDATA[
2555 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
2556 Validator v = new Validator(is,
2557 (new File(myDTD)).toURI().toURL().toString());
2558 boolean isValid = v.isValid();
2559 ]]></programlisting></example>
2560 </listitem>
2561
2562 <listitem>Use a custom <literal>EntityResolver</literal> via
2563 <literal>XMLUnit.setControlEntityResolver</literal> together
2564 with one of the single argument constructor overloads of
2565 Validator.
2566
2567 <para>This approach would allow you to use an OASIS
2568 catalog<footnote><para><ulink
2569 url="http://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html">http://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html</ulink></para></footnote>
2570 in conjunction with the Apache XML Resolver
2571 library<footnote><para><ulink
2572 url="http://xml.apache.org/commons/components/resolver/index.html">http://xml.apache.org/commons/components/resolver/index.html</ulink></para></footnote>
2573 to resolve the DTD location as well as the location of any
2574 other entity in your piece of XML, for example.</para>
2575
2576 <example>
2577 <title>Validating Against a DTD Using Apache's XML Resolver and
2578 an XML Catalog</title>
2579 <programlisting language="Java"><![CDATA[
2580 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
2581 XMLUnit.setControlEntityResolver(new CatalogResolver());
2582 Validator v = new Validator(is);
2583 boolean isValid = v.isValid();
2584 ]]></programlisting>
2585
2586 <programlisting><![CDATA[
2587 #CatalogManager.properties
2588
2589 verbosity=1
2590 relative-catalogs=yes
2591 catalogs=/some/path/to/catalog
2592 prefer=public
2593 static-catalog=yes
2594 catalog-class-name=org.apache.xml.resolver.Resolver
2595 ]]></programlisting>
2596
2597 <programlisting language="XML"><![CDATA[
2598 <!-- catalog file -->
2599
2600 <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
2601 <public publicId="-//Some//DTD V 1.1//EN"
2602 uri="mydtd.dtd"/>
2603 </catalog>
2604 ]]></programlisting>
2605
2606 </example>
2607
2608 </listitem>
2609 </itemizedlist>
2610
2611 <section id="XML Schema Validation">
2612 <title>XML Schema Validation</title>
2613 </section>
2614
2615 <para>In order to validate against the XML Schema language
2616 Schema validation has to be enabled via the
2617 <literal>useXMLSchema</literal> method of
2618 <literal>Validator</literal>.</para>
2619
2620 <para>By default the parser will try to resolve the location of
2621 Schema definition files via a <literal>schemaLocation</literal>
2622 attribute if it is present in the piece of XML or it will try to
2623 open the Schema's URI as an URL and read from it.</para>
2624
2625 <para>The <literal>setJAXP12SchemaSource</literal> method of
2626 <literal>Validator</literal> allows you to override this
2627 behavior as long as the parser supports the
2628 <literal>http://java.sun.com/xml/jaxp/properties/schemaSource</literal>
2629 property in the way described in "JAXP 1.2 Approved
2630 CHANGES"<footnote><para><ulink
2631 url="http://java.sun.com/webservices/jaxp/change-requests-11.html">http://java.sun.com/webservices/jaxp/change-requests-11.html</ulink></para></footnote>.</para>
2632
2633 <para><literal>setJAXP12SchemaSource</literal>'s argument can be
2634 one of</para>
2635
2636 <itemizedlist>
2637 <listitem>A <literal>String</literal> which contains an
2638 URI.</listitem>
2639 <listitem>An <literal>InputStream</literal> the Schema can be
2640 read from.</listitem>
2641 <listitem>An <literal>InputSource</literal> the Schema can be
2642 read from.</listitem>
2643 <listitem>A <literal>File</literal> the Schema can be
2644 read from.</listitem>
2645 <listitem>An array containing any of the above.</listitem>
2646 </itemizedlist>
2647
2648 <para>If the property has been set using a
2649 <literal>String</literal>, the <literal>Validator</literal>
2650 class will provide its <literal>systemId</literal> as specified
2651 in the constructor when asked to resolve it. You must only use
2652 the single argument constructors if you want to avoid this
2653 behavior. If no <literal>systemId</literal> has been specified,
2654 the configured <literal>EntityResolver</literal> may still be
2655 used.</para>
2656
2657 <example id="schema-jaxp12">
2658 <title>Validating Against a Local XML Schema</title>
2659 <programlisting language="Java"><![CDATA[
2660 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
2661 Validator v = new Validator(is);
2662 v.useXMLSchema(true);
2663 v.setJAXP12SchemaSource(new File(myXmlSchemaFile));
2664 boolean isValid = v.isValid();
2665 ]]></programlisting></example>
2666
2667 </section>
2668
2669 <section id="Validation: JUnit 3">
2670 <title>JUnit 3.x Convenience Methods</title>
2671
2672 <para>Both <literal>XMLAssert</literal> and
2673 <literal>XMLTestCase</literal> provide an
2674 <literal>assertXMLValid(Validator)</literal> method that will
2675 fail if <literal>Validator</literal>'s
2676 <literal>isValid</literal> method returns
2677 <literal>false</literal>.</para>
2678
2679 <para>In addition several overloads of the
2680 <literal>assertXMLValid</literal> method are provided that
2681 directly correspond to similar overloads of
2682 <literal>Validator</literal>'s constructor. These overloads
2683 don't support XML Schema validation at all.</para>
2684
2685 <para><literal>Validator</literal> itself provides an
2686 <literal>assertIsValid</literal> method that will throw an
2687 <literal>AssertionFailedError</literal> if validation
2688 fails.</para>
2689
2690 <para>Neither method provides any control over the message of
2691 the <literal>AssertionFailedError</literal> in case of a
2692 failure.</para>
2693 </section>
2694
2695 <section id="Validation: Configuration">
2696 <title>Configuration Options</title>
2697
2698 <itemizedlist>
2699 <listitem><literal>Validator</literal> uses a SAX parser
2700 created by the configured SAX parser factory (see <xref
2701 linkend="JAXP"/>).</listitem>
2702
2703 <listitem>It will use the "control"
2704 <literal>EntityResolver</literal> if one has been specified
2705 (see <xref linkend="EntityResolver"/>).</listitem>
2706
2707 <listitem>The location of a DTD can be specified via
2708 <literal>Validator</literal>'s <literal>systemId</literal>
2709 constructor argument or a custom EntityResolver (see <xref
2710 linkend="DTD Validation"/>).</listitem>
2711
2712 <listitem>XML Schema validation is enabled via
2713 <literal>Validator.useXMLSchema(true)</literal>.</listitem>
2714
2715 <listitem>The location(s) of XML Schema document(s) can be
2716 specified via
2717 <literal>Validator.setJAXP12SchemaSource</literal> (see <xref
2718 linkend="XML Schema Validation"/>).</listitem>
2719 </itemizedlist>
2720 </section>
2721
2722 <section id="JAXP 1.3 Validation">
2723 <title>JAXP 1.3 Validation</title>
2724
2725 <para>JAXP 1.3 - shipping with Java5 or better and available as
2726 a separate product for earlier Java VMs - introduces a new
2727 package <ulink url="https://jaxp-sources.dev.java.net/nonav/docs/api/"><literal>javax.xml.validation</literal></ulink>
2728 designed for validations of snippets of XML against different
2729 schema languages. Any compliant implementation must support the
2730 W3C XML Schema language, but other languages
2731 like <ulink url="http://www.relaxng.org/">RELAX NG</ulink> or
2732 <ulink url="http://www.schematron.com/">Schematron</ulink> may
2733 be supported as well.</para>
2734
2735 <para>The
2736 class <literal>org.custommonkey.xmlunit.jaxp13.Validator</literal>
2737 can be used to validate a piece of XML against a schema
2738 definition but also to validate the schema definition itself.
2739 By default <literal>Validator</literal> will assume your
2740 definition uses the W3C XML Schema language, but it provides a
2741 constructor that can be used to specify a different language via
2742 an URL supported by the <literal>SchemaFactory</literal> class.
2743 Alternatively you can specify the schema factory itself.</para>
2744
2745 <para>The schema definition itself can be given via
2746 <literal>Source</literal> elements, just like the pieces of XML
2747 to validate are specified as <literal>Source</literal> as
2748 well.</para>
2749
2750 <para>Note the <literal>Validator</literal> class
2751 of <literal>javax.xml.validation</literal> will ignore all
2752 <literal>xsi:namespaceLocation</literal> and
2753 <literal>xsi:noNamespaceLocation</literal> attributes of the XML
2754 document you want to validate if you specify at least one schema
2755 source.</para>
2756
2757 <para>The following example
2758 uses <literal>org.custommonkey.xmlunit.jaxp13.Validator</literal>
2759 to perform the same type of validation shown in
2760 <xref linkend="schema-jaxp12"/>.</para>
2761
2762 <example id="schema-jaxp13">
2763 <title>Validating Against a Local XML Schema</title>
2764 <programlisting language="Java"><![CDATA[
2765 Validator v = new Validator();
2766 v.addSchemaSource(new StreamSource(new File(myXmlSchemaFile)));
2767 StreamSource is = new StreamSource(new File(myXmlDocument));
2768 boolean isValid = v.isInstanceValid(is);
2769 ]]></programlisting></example>
2770
2771 <para>Validating a schema definition is shown in the next
2772 example.</para>
2773
2774 <example>
2775 <title>Validating an XML Schema Definition</title>
2776 <programlisting language="Java"><![CDATA[
2777 Validator v = new Validator();
2778 v.addSchemaSource(new StreamSource(new File(myXmlSchemaFile)));
2779 boolean isValid = v.isSchemaValid();
2780 ]]></programlisting></example>
2781
2782 <para>There is no explicit JUnit 3 support
2783 for <literal>org.custommonkey.xmlunit.jaxp13.Validator</literal>.</para>
2784
2785 </section>
2786
2787 </section>
2788
2789 <section id="XPath Tests">
2790 <title>XPath Tests</title>
2791
2792 <section id="XPath Engines">
2793 <title>XPath Engines</title>
2794
2795 <para>Central to XMLUnit's XPath support is the
2796 <literal>XpathEngine</literal> interface which consists of only
2797 three methods:</para>
2798
2799 <programlisting language="Java"><![CDATA[
2800 /**
2801 * Execute the specified xpath syntax <code>select</code> expression
2802 * on the specified document and return the list of nodes (could have
2803 * length zero) that match
2804 * @param select
2805 * @param document
2806 * @return list of matching nodes
2807 */
2808 NodeList getMatchingNodes(String select, Document document)
2809 throws XpathException;
2810
2811 /**
2812 * Evaluate the result of executing the specified XPath syntax
2813 * <code>select</code> expression on the specified document
2814 * @param select
2815 * @param document
2816 * @return evaluated result
2817 */
2818 String evaluate(String select, Document document)
2819 throws XpathException;
2820
2821 /**
2822 * Establish a namespace context.
2823 */
2824 void setNamespaceContext(NamespaceContext ctx);
2825 ]]></programlisting>
2826
2827
2828 <para>The first two methods expect an XPath expression that
2829 selects content from the DOM document that is the second
2830 argument. The result of the selection can be either a DOM
2831 <literal>NodeList</literal> or a <literal>String</literal>. The
2832 later form tries to flatten the result, the value is said to be
2833 "String-ified".</para>
2834
2835 <para>The third method is part of XMLUnit's support for XML
2836 Namespaces in XPath expressions. See <xref linkend="Using XML Namespaces in XPath Selectors"/>
2837 for more details.</para>
2838
2839 <para>There are two implementations of the interface,
2840 <literal>org.custommonkey.xmlunit.SimpleXpathEngine</literal>
2841 and
2842 <literal>org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</literal>.
2843 The first implementation is the only one available in XMLUnit
2844 1.0 and uses the <link linked="JAXP">configured</link> JAXP XSLT
2845 transformer. The second is new to XMLUnit 1.1 and only
2846 available if JAXP 1.3 or later is supported, which should be the
2847 case for Java 5 and later.</para>
2848
2849 <para><literal>XpathException</literal> is an
2850 <literal>Exception</literal> that will be thrown for invalid
2851 XPath expressions or other problems with the underlying XPath
2852 engine. It will typically wrap a
2853 <literal>javax.xml.xpath.XPathExpressionException</literal> in
2854 the <literal>Jaxp13XpathEngine</literal> case or a
2855 <literal>javax.xml.transform.TransformerException</literal> when
2856 <literal>SimpleXpathEngine</literal> is used.</para>
2857
2858 <para>The <literal>XMLUnit.newXpathEngine</literal> method will
2859 first try to create an instance of
2860 <literal>Jaxp13XpathEngine</literal> and fall back to
2861 <literal>SimpleXpathEngine</literal> if JAXP 1.3 is not
2862 supported.</para>
2863
2864 <para>One example of using the XPath support is included inside
2865 it <literal>org.custommonkey.xmlunit.examples</literal> package.
2866 It asserts that the string-ified form of an XPath selection
2867 matches a regular expression. The code needed for this
2868 is:</para>
2869
2870 <example>
2871 <title>Matching an XPath Selection Against a Regular
2872 Expression</title>
2873 <programlisting language="Java"><![CDATA[
2874 XpathEngine engine = XMLUnit.newXpathEngine();
2875 String value = engine.evaluate(xpath, doc);
2876 Assert.assertTrue(message, value.matches(regex));
2877 ]]></programlisting></example>
2878
2879 </section>
2880
2881 <section id="Using XML Namespaces in XPath Selectors">
2882 <title>Using XML Namespaces in XPath Selectors</title>
2883
2884 <para>Starting with XMLUnit 1.1 XML Namespaces are supported for
2885 XPath queries.</para>
2886
2887 <para>The <literal>NamespaceContext</literal> interface provides
2888 a mapping from prefix to namespace URI and is used by the XPath
2889 engine. XPath selections then use the mapping's prefixes where
2890 needed. Note that a prefix used in the document under test and
2891 a prefix given as part of the
2892 <literal>NamespaceContext</literal> are not related at all; the
2893 context only applies to the XPath expression, the prefix used in
2894 the document is ignored completely.</para>
2895
2896 <para>Right now XMLUnit provides only a single implementation of
2897 the <literal>NamespaceContext</literal> interface:
2898 <literal>SimpleNamespaceContext</literal>. This implementation
2899 expects a <literal>java.util.Map</literal> as its constructor
2900 argument. The <literal>Map</literal> must contain
2901 (<literal>String</literal>) prefixes as keys and
2902 (<literal>String</literal>) namespace URIs as values.</para>
2903
2904 <para>Note there is nothing like a default namespace in XPath
2905 selectors. If you are using namespaces in your XPath, all
2906 namespaces need a prefix (of length greater than zero). This
2907 is independent of the prefixes used in your document.</para>
2908
2909 <para>The following example is taken from XMLUnit's own tests.
2910 It demonstrates that the namespace prefix of the document under
2911 test is irrelevant and shows how to set up the namespace
2912 context.</para>
2913
2914 <example>
2915 <title>Using Namespaces in XPath Tests</title>
2916 <programlisting language="Java"><![CDATA[
2917 String testDoc = "<t:test xmlns:t=\"urn:foo\"><t:bar/></t:test>";
2918 Document d = XMLUnit.buildControlDocument(testDoc);
2919 HashMap m = new HashMap();
2920 m.put("foo", "urn:foo");
2921
2922 NamespaceContext ctx = new SimpleNamespaceContext(m);
2923 XpathEngine engine = XMLUnit.newXpathEngine();
2924 engine.setNamespaceContext(ctx);
2925
2926 NodeList l = engine.getMatchingNodes("//foo:bar", d);
2927 assertEquals(1, l.getLength());
2928 assertEquals(Node.ELEMENT_NODE, l.item(0).getNodeType());
2929 ]]></programlisting></example>
2930
2931 <para>In some cases the "stringified" value of an XPath
2932 evaluation is a qualified name - a string that encodes a
2933 namespace URI together with a local name. There are two common
2934 formats for such qualified names, one used by Java5's
2935 <literal>QName</literal> in the format
2936 <literal>{NS-URI}LOCAL-NAME</literal> and one using
2937 <literal>PREFIX:LOCAL-NAME</literal>. Starting with XMLUnit 1.6
2938 a new <literal>QualifiedName</literal> class can parse either
2939 representation. The <literal>assertXpathEvaluatesTo</literal>
2940 overloads where the expected value is a
2941 <literal>QualifiedName</literal> try to parse the stringified
2942 value in either format - using the documents namespace context
2943 when parsing the actual value.</para>
2944
2945 <para>It is possible to set a global
2946 <literal>NamespaceContext</literal>, see <xref
2947 linkend="XPath: Configuration"/> for details.</para>
2948 </section>
2949
2950 <section id="XPath: JUnit 3">
2951 <title>JUnit 3.x Convenience Methods</title>
2952
2953 <para><literal>XMLTestCase</literal> and
2954 <literal>XMLAssert</literal> provide several overloads for the
2955 following common types of assertions:</para>
2956
2957 <itemizedlist>
2958
2959 <listitem>Two XPath expression should return the same DOM
2960 <literal>NodeList</literal> as result:
2961 <literal>assertXpathsEqual</literal>. There are methods that
2962 use two different expressions on the same document and others
2963 that compare expressions selecting from two different
2964 documents.
2965
2966 <para>The <literal>NodeList</literal>s are wrapped into a
2967 surrogate root XML element and the resulting DOM
2968 <literal>Document</literal>s are compared using
2969 <literal>Diff.similar()</literal>.</para>
2970 </listitem>
2971
2972 <listitem>The opposite of the above, the expressions should
2973 yield different results:
2974 <literal>assertXpathsNotEqual</literal>.</listitem>
2975
2976 <listitem>Two XPath expression should return the same
2977 "String-ified" result:
2978 <literal>assertXpathValuesEqual</literal>. There are methods
2979 that use two different expressions on the same document and
2980 others that compare expressions selecting from two different
2981 documents.</listitem>
2982
2983 <listitem>The opposite of the above, the expressions should
2984 yield different results:
2985 <literal>assertXpathValuesNotEqual</literal>.</listitem>
2986
2987 <listitem>The XPath expression should return an expected value
2988 when "String-ified" or interpreted as qualified name:
2989 <literal>assertXpathEvaluatesTo</literal>.</listitem>
2990
2991 <listitem>The <literal>NodeList</literal> selected by an XPath
2992 expression is not empty:
2993 <literal>assertXpathExists</literal>.</listitem>
2994
2995 <listitem>The <literal>NodeList</literal> selected by an XPath
2996 expression is empty:
2997 <literal>assertXpathNotExists</literal>.</listitem>
2998 </itemizedlist>
2999
3000 <para>Neither method provides any control over the message of
3001 the <literal>AssertionFailedError</literal> in case of a
3002 failure.</para>
3003 </section>
3004
3005 <section id="XPath: Configuration">
3006 <title>Configuration Options</title>
3007
3008 <para>When using <literal>XpathEngine</literal> directly you are
3009 responsible for creating the DOM document yourself. If you use
3010 the convenience methods of <literal>XMLTestCase</literal> or
3011 <literal>XMLAssert</literal> you have several options to specify
3012 the input; XMLUnit will use the control or test parser that has
3013 been configured (see <xref linkend="JAXP"/>) to create a DOM
3014 document from the given piece of XML in that case - using the
3015 configured <literal>EntityResolver</literal>(s) (see <xref
3016 linkend="EntityResolver"/>) if any.</para>
3017
3018 <para>If JAXP 1.3 is not available,
3019 <literal>SimpleXpathEngine</literal> will use the configured
3020 JAXP XSLT transformer (see <xref linkend="JAXP"/>) under the
3021 covers.</para>
3022
3023 <para>When using JAXP 1.3 you can chose the actual
3024 <literal>XPathFactory</literal> implementation using
3025 <literal>XMLUnit.setXPathFactory</literal>.</para>
3026
3027 <para>It is possible to establish a global
3028 <literal>NamespaceContext</literal> with the help of the
3029 <literal>XMLUnit.setXpathNamespaceContext</literal> method. Any
3030 <literal>XpathEngine</literal> created by
3031 <literal>XMLUnit.newXpathEngine</literal> will automatically use
3032 the given context. Note that the JUnit 3 convenience methods
3033 use <literal>XMLUnit.newXpathEngine</literal> implicitly and
3034 will thus use the configured
3035 <literal>NamespaceContext</literal>.</para>
3036
3037 </section>
3038 </section>
3039
3040 <section id="DOM Tree Walking">
3041 <title>DOM Tree Walking</title>
3042
3043 <para>Sometimes it is easier to test a piece of XML's validity by
3044 traversing the whole document node by node and test each node
3045 individually. Maybe there is no control XML to validate against
3046 or the expected value of an element's content has to be
3047 calculated. There may be several reasons.</para>
3048
3049 <para>XMLUnit supports this approach of testing via the
3050 <literal>NodeTest</literal> class. In order to use it, you need a
3051 DOM implementation that generates <literal>Document</literal>
3052 instances that implement the optional
3053 <literal>org.w3c.traversal.DocumentTraversal</literal> interface,
3054 which is not part of JAXP's standardized DOM support.</para>
3055
3056 <section id="DocumentTraversal">
3057 <title><literal>DocumentTraversal</literal></title>
3058
3059 <para>As of the release of XMLUnit 1.1 the
3060 <literal>Document</literal> instances created by most parsers
3061 implement <literal>DocumentTraversal</literal>, this includes
3062 but is not limited to Apache Xerces, the parser shipping with
3063 Sun's JDK 5 and later or GNU JAXP. One notable exception is
3064 Apache Crimson, which also means the parser shipping with Sun's
3065 JDK 1.4 does not support traversal; you need to specify a
3066 different parser when using JDK 1.4 (see <xref
3067 linkend="JAXP"/>).</para>
3068
3069 <para>You can test whether your XML parser supports
3070 <literal>DocumentTraversal</literal> by invoking
3071 <literal>org.w3c.dom.DOMImplementation</literal>'s
3072 <literal>hasFeature</literal> method with the feature
3073 <literal>"Traversal"</literal>.</para>
3074 </section>
3075
3076 <section id="NodeTest">
3077 <title><literal>NodeTest</literal></title>
3078
3079 <para>The <literal>NodeTest</literal> is instantiated with a
3080 piece of XML to traverse. It offers two
3081 <literal>performTest</literal> methods:</para>
3082
3083 <programlisting language="Java"><![CDATA[
3084 /**
3085 * Does this NodeTest pass using the specified NodeTester instance?
3086 * @param tester
3087 * @param singleNodeType note <code>Node.ATTRIBUTE_NODE</code> is not
3088 * exposed by the DocumentTraversal node iterator unless the root node
3089 * is itself an attribute - so a NodeTester that needs to test attributes
3090 * should obtain those attributes from <code>Node.ELEMENT_NODE</code>
3091 * nodes
3092 * @exception NodeTestException if test fails
3093 */
3094 public void performTest(NodeTester tester, short singleNodeType);
3095
3096 /**
3097 * Does this NodeTest pass using the specified NodeTester instance?
3098 * @param tester
3099 * @param nodeTypes note <code>Node.ATTRIBUTE_NODE</code> is not
3100 * exposed by the DocumentTraversal node iterator unless the root node
3101 * is itself an attribute - so a NodeTester that needs to test attributes
3102 * should obtain those attributes from <code>Node.ELEMENT_NODE</code>
3103 * nodes instead
3104 * @exception NodeTestException if test fails
3105 */
3106 public void performTest(NodeTester tester, short[] nodeTypes);
3107 ]]></programlisting>
3108
3109 <para><literal>NodeTester</literal> is the class testing each
3110 node and is described in the next section.</para>
3111
3112 <para>The second argument limits the tests on DOM
3113 <literal>Node</literal>s of (a) specific type(s).
3114 <literal>Node</literal> types are specified via the
3115 <literal>static</literal> fields of the <literal>Node</literal>
3116 class. Any <literal>Node</literal> of a type not specified as
3117 the second argument to <literal>performTest</literal> will be
3118 ignored.</para>
3119
3120 <para>Unfortunately XML attributes are not exposed as
3121 <literal>Node</literal>s during traversal. If you need access
3122 to attributes you must add <literal>Node.ELEMENT_NODE</literal>
3123 to the second argument of <literal>performTest</literal> and
3124 access the attributes from their parent
3125 <literal>Element</literal>.</para>
3126
3127 <example id="nodetest-attributes">
3128 <title>Accessing Attributes in a
3129 <literal>NodeTest</literal></title>
3130 <programlisting language="Java"><![CDATA[
3131 ...
3132 NodeTest nt = new NodeTest(myXML);
3133 NodeTester tester = new MyNodeTester();
3134 nt.performTest(tester, Node.ELEMENT_NODE);
3135 ...
3136
3137 class MyNodeTester implements NodeTester {
3138 public void testNode(Node aNode, NodeTest test) {
3139 Element anElement = (Element) aNode;
3140 Attr attributeToTest = anElement.getAttributeNode(ATTRIBUTE_NAME);
3141 ...
3142 }
3143 ...
3144 }
3145 ]]></programlisting></example>
3146
3147 <para>Any entities that appear as part of the
3148 <literal>Document</literal> are expanded before the traversal
3149 starts.</para>
3150
3151 </section>
3152
3153 <section id="NodeTester">
3154 <title>NodeTester</title>
3155
3156 <para>Implementations of the <literal>NodeTester</literal>
3157 interface are responsible for the actual test:</para>
3158
3159 <programlisting language="Java"><![CDATA[
3160 /**
3161 * Validate a single Node
3162 * @param aNode
3163 * @param forTest
3164 * @exception NodeTestException if the node fails the test
3165 */
3166 void testNode(Node aNode, NodeTest forTest) throws NodeTestException ;
3167
3168 /**
3169 * Validate that the Nodes passed one-by-one to the <code>testNode</code>
3170 * method were all the Nodes expected.
3171 * @param forTest
3172 * @exception NodeTestException if this instance was expecting more nodes
3173 */
3174 void noMoreNodes(NodeTest forTest) throws NodeTestException ;
3175 ]]></programlisting>
3176
3177 <para><literal>NodeTest</literal> invokes
3178 <literal>testNode</literal> for each <literal>Node</literal> as
3179 soon as it is reached on the traversal. This means
3180 <literal>NodeTester</literal> "sees" the
3181 <literal>Node</literal>s in the same order they appear within
3182 the tree.</para>
3183
3184 <para><literal>noMoreNodes</literal> is invoked when the
3185 traversal is finished. It will also be invoked if the tree didn't
3186 contain any matched <literal>Node</literal>s at all.</para>
3187
3188 <para>Implementations of <literal>NodeTester</literal> are
3189 expected to throw a <literal>NodeTestException</literal> if the
3190 current not doesn't match the test's expectations or more nodes
3191 have been expected when <literal>noMoreNodes</literal> is
3192 called.</para>
3193
3194 <para>XMLUnit ships with two implementations of
3195 <literal>NodeTest</literal> that are described in the following
3196 to sections.</para>
3197
3198 <section id="AbstractNodeTester">
3199 <title><literal>AbstractNodeTester</literal></title>
3200
3201 <para><literal>AbstractNodeTester</literal> implements
3202 <literal>testNode</literal> by testing the passed in
3203 <literal>Node</literal> for its type and delegating to one of
3204 the more specific <literal>test...</literal> Methods it adds.
3205 By default the new <literal>test...</literal> methods all
3206 throw a <literal>NodeTestException</literal> because of an
3207 unexpected <literal>Node</literal>.</para>
3208
3209 <para>It further implements <literal>noMoreNodes</literal>
3210 with an empty method - i.e. it does nothing.</para>
3211
3212 <para>If you are only testing for specific types of
3213 <literal>Node</literal> it may be more convenient to subclass
3214 <literal>AbstractNodeTester</literal>. For example <xref
3215 linkend="nodetest-attributes"/> could be re-written as:</para>
3216
3217 <example>
3218 <title>Accessing Attributes in a
3219 <literal>NodeTest</literal> -
3220 <literal>AbstractNodeTester</literal> version</title>
3221 <programlisting language="Java"><![CDATA[
3222 ...
3223 NodeTest nt = new NodeTest(myXML);
3224 NodeTester tester = new AbstractNodeTester() {
3225 public void testElement(Element element) throws NodeTestException {
3226 Attr attributeToTest = element.getAttributeNode(ATTRIBUTE_NAME);
3227 ...
3228 }
3229 };
3230 nt.performTest(tester, Node.ELEMENT_NODE);
3231 ...
3232 ]]></programlisting></example>
3233
3234 <para>Note that even though
3235 <literal>AbstractNodeTester</literal> contains a
3236 <literal>testAttribute</literal> method it will never be
3237 called by default and you still need to access attributes via
3238 their parent elements.</para>
3239
3240 <para>Note also that the root of the test is the document's
3241 root element, so any <literal>Node</literal>s preceding the
3242 document's root <literal>Element</literal> won't be visited
3243 either. For this reason the
3244 <literal>testDocumentType</literal>,
3245 <literal>testEntity</literal> and
3246 <literal>testNotation</literal> methods are probably never
3247 called either.</para>
3248
3249 <para>Finally, all entity references have been expanded before
3250 the traversal started. <literal>EntityReference</literal>s
3251 will have been replaced by their replacement text if it is
3252 available, which means <literal>testEntityReference</literal>
3253 will not be called for them either. Instead the replacement
3254 text will show up as (part of) a <literal>Text</literal> node
3255 or as <literal>Element</literal> node, depending on the
3256 entity's definition.</para>
3257 </section>
3258
3259 <section id="CountingNodeTester">
3260 <title><literal>CountingNodeTester</literal></title>
3261
3262 <para><literal>org.custommonkey.xmlunit.examples.CountingNodeTester</literal>
3263 is a simple example <literal>NodeTester</literal> that asserts
3264 that a given number of <literal>Node</literal>s have been
3265 traversed. It will throw a
3266 <literal>NodeTestException</literal> when
3267 <literal>noMoreNodes</literal> is called before the expected
3268 number of <literal>Node</literal>s has been visited or the
3269 actual number of nodes exceeded the expected count.</para>
3270 </section>
3271 </section>
3272
3273 <section id="DOM Tree: JUnit 3">
3274 <title>JUnit 3.x Convenience Methods</title>
3275
3276 <para><literal>XMLAssert</literal> and
3277 <literal>XMLTestCase</literal> contain overloads of
3278 <literal>assertNodeTestPasses</literal> methods.</para>
3279
3280 <para>The most general form of it expects you to create a
3281 <literal>NodeTest</literal> instance yourself and lets you
3282 specify whether you expect the test to fail or to pass.</para>
3283
3284 <para>The other two overloads create a
3285 <literal>NodeTest</literal> instance from either
3286 <literal>String</literal> or a SAX
3287 <literal>InputSource</literal> and are specialized for the case
3288 where you are only interested in a single <literal>Node</literal>
3289 type and expect the test to pass.</para>
3290
3291 <para>Neither method provides any control over the message of
3292 the <literal>AssertionFailedError</literal> in case of a
3293 failure.</para>
3294 </section>
3295
3296 <section id="DOM Tree: Configuration">
3297 <title>Configuration Options</title>
3298
3299 <para>The only configurable option for
3300 <literal>NodeTest</literal> is the XML parser used if the piece
3301 of XML is not specified as a <literal>Document</literal> or
3302 <literal>DocumentTraversal</literal>.
3303 <literal>NodeTest</literal> will use the "control" parser that
3304 has been configured - see <xref linkend="JAXP"/> for
3305 details.</para>
3306
3307 <para>It will also use the <literal>EntityResolver</literal>
3308 configured for the control parser if one has been set - see
3309 <xref linkend="EntityResolver"/>.</para>
3310 </section>
3311
3312 </section>
3313
3314 <appendix id="changes">
3315 <title>Changes</title>
3316
3317 <section id="Changes 1.1">
3318 <title>Changes from XMLUnit 1.0 to 1.1</title>
3319
3320 <para>XMLUnit 1.1's main focus was to add two features that have
3321 been asked for repeatedly:</para>
3322
3323 <itemizedlist>
3324 <listitem>Support for XML Namespaces in XPath
3325 processing</listitem>
3326
3327 <listitem>Support for XML Schema validation.</listitem>
3328 </itemizedlist>
3329
3330 <para>In addition some JAXP features that have been added after
3331 the release of XMLUnit 1.0 are now supported - most notably
3332 XPath support - and all reported bugs and feature requests have
3333 been addressed.</para>
3334
3335 <section id="Breaking Changes 1.1">
3336 <title>Breaking Changes</title>
3337
3338 <itemizedlist>
3339 <listitem>
3340 <literal>XMLTestCase</literal> is now abstract. You
3341 probably have never created instances of this class
3342 without subclassing it, but if you did, your code will now
3343 break. You will most likely want to look at the
3344 <literal>XMLAssert</literal> class.
3345 </listitem>
3346
3347 <listitem>
3348 <para>All methods that have been deprecated in XMLUnit 1.0
3349 have been removed.</para>
3350 </listitem>
3351
3352 <listitem>
3353 <para>All methods that had been declared to throw
3354 <literal>TransformerConfigurationException</literal> or
3355 <literal>ParserConfigurationException</literal> now no
3356 longer declare it. Exceptions of these types cannot be
3357 recovered from anyway, so XMLUnit will now wrap them in a
3358 <literal>org.custommonkey.xmlunit.exceptions.ConfigurationException</literal>
3359 which is an unchecked exception.</para>
3360
3361 <para>This change doesn't have a big impact on your tests,
3362 but if you tried to catch these exceptions they will now
3363 bypass your catch blocks.</para>
3364 </listitem>
3365
3366 <listitem>
3367 <para>A new type of <literal>Difference</literal>
3368 (<literal>CHILD_NODE_NOT_FOUND_ID</literal>) has been
3369 added. It will be raised for the excess children if the
3370 control element has more child nodes than the test element
3371 - or vice versa.</para>
3372
3373 <para>Prior to XMLUnit 1.1 a <literal>Difference</literal>
3374 of either <literal>ELEMENT_TAG_NAME_ID</literal> or
3375 <literal>NODE_TYPE_ID</literal> would have been raised if
3376 the control element had more children. The excess
3377 children were compared to the very first child node of the
3378 test element. Excess children of the test element were
3379 not reported at all.</para>
3380 </listitem>
3381
3382 <listitem>
3383 <para>The <literal>schemaLocation</literal> and
3384 <literal>noNamespaceSchemaLocation</literal> attributes of
3385 the XMLSchema-Instance Namespace are now treated in a
3386 different way from "normal" attributes. They will be
3387 flagged as new kinds of <literal>Difference</literal> that
3388 is recoverable.</para>
3389
3390 <para>This means that two pieces of XML that were
3391 different in XMLUnit 1.0 because they differed in one of
3392 the two attributes will be similar in XMLUnit 1.1.</para>
3393 </listitem>
3394
3395 <listitem>
3396 <para>When comparing two elements that differ on
3397 attributes the comparison is now symmetric.</para>
3398
3399 <para>In XMLUnit 1.0 if an attribute was present on the
3400 test but not the control element this wasn't flagged as a
3401 <literal>Difference</literal>; in XMLUnit 1.1 it
3402 is.</para>
3403
3404 <para>In most practical cases this doesn't cause any
3405 problems since the two elements either have a different
3406 number of attributes or there are attributes in the
3407 control element that are missing in the test element - so
3408 the pieces of XML have been flagged as different before as
3409 well. If you are using <literal>DetailedDiff</literal>
3410 this change may lead to more detected
3411 <literal>Difference</literal>s, though.</para>
3412 </listitem>
3413 </itemizedlist>
3414 </section>
3415
3416 <section id="New Features 1.1">
3417 <title>New Features</title>
3418
3419 <itemizedlist>
3420 <listitem>XMLUnit 1.0 shipped with rudimentary support for
3421 XML Schema validation (it worked with Apache Xerces-J but no
3422 other parsers). XMLUnit 1.1 supports Schema validation for
3423 any JAXP compliant XML parser (that supports Schema itself).
3424 You can also tell XMLUnit where to look for the XML Schema
3425 definitions. See <xref linkend="XML Schema Validation"/> for
3426 details.</listitem>
3427
3428 <listitem>XPath support has undergone significant changes,
3429 see <xref linkend="XPath Tests"/> for more details. In particular
3430 XMLUnit will now use <literal>javax.xml.xpath</literal> if
3431 it is available (which also helps to avoid the buggy XSLTC
3432 version that is the default transformer engine in Java 5)
3433 and supports XML namespaces.</listitem>
3434
3435 <listitem>Several new configuration options have been added,
3436 see <xref linkend="Comparing: Configuration"/>.
3437 <itemizedlist>
3438 <listitem>Treat CDATA sections and Texts alike. <ulink
3439 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1262148&amp;group_id=23187&amp;atid=377768">Issue
3440 1262148</ulink>.</listitem>
3441
3442 <listitem>Ignore differences in Text whitespace. <ulink
3443 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=754812&amp;group_id=23187&amp;atid=377771">Issue
3444 754812</ulink>.</listitem>
3445
3446 <listitem>Ignore comments completely. <ulink
3447 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=707255&amp;group_id=23187&amp;atid=377770">Issue
3448 707255</ulink>.</listitem>
3449
3450 <listitem>Ignore the order of attributes.</listitem>
3451 </itemizedlist>
3452 </listitem>
3453
3454 <listitem>It is now possible to provide a custom
3455 <literal>org.xml.sax.EntityResolver</literal> for control
3456 and test parsers.</listitem>
3457
3458 <listitem>It is now possible to provide a custom
3459 <literal>javax.xml.transform.URIResolver</literal> for
3460 transformations.</listitem>
3461
3462 <listitem>New overloads have been added that allow
3463 <literal>org.xml.sax.InputSource</literal> to be used as a
3464 "piece of XML" in many classes.</listitem>
3465
3466 <listitem><literal>Validator</literal> will now use the
3467 custom <literal>EntityResolver</literal> <link
3468 linkend="EntityResolver">configured</link> for the "control"
3469 parser as a fallback.</listitem>
3470
3471 <listitem>
3472 <para>A new package
3473 <literal>org.custommonkey.xmlunit.examples</literal> has
3474 been added that showcases some of XMLUnit's abilities.
3475 It currently contains two classes:</para>
3476
3477 <orderedlist>
3478 <listitem>
3479 <literal>MultiLevelElementNameAndTextQualifier</literal>
3480 see <xref
3481 linkend="MultiLevelElementNameAndTextQualifier"/> for
3482 a description.</listitem>
3483
3484 <listitem><literal>XPathRegexAssert</literal> that
3485 provides a JUnit 3.x like
3486 <literal>assertXPathMatches</literal> method to verify
3487 that the string-ified value of an XPath match matches a
3488 given regular expression (requires JDK 1.4 or
3489 above).</listitem>
3490 </orderedlist>
3491 </listitem>
3492 </itemizedlist>
3493 </section>
3494
3495 <section id="Bugfixes 1.1">
3496 <title>Important Bug Fixes</title>
3497
3498 <itemizedlist>
3499 <listitem><literal>ElementNameAndAttributeQualifier</literal>
3500 would throw an <literal>NullPointerException</literal> if
3501 the control piece of XML contained attributes that were
3502 missing in the test piece of XML. <ulink
3503 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=952920&amp;group_id=23187&amp;atid=377768">Issue
3504 952920</ulink>.</listitem>
3505
3506 <listitem>
3507 <literal>XMLTestCase.assertXMLNotEqual(String, Reader,
3508 Reader)</literal> delegated to
3509 <literal>assertXMLEqual</literal> instead of
3510 <literal>assertXMLNotEqual</literal> internally, negating
3511 the assertion's logic. <ulink
3512 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=956372&amp;group_id=23187&amp;atid=377768">Issue
3513 956372</ulink>.</listitem>
3514
3515 <listitem><literal>XMLTestCase.assertXMLIdentical(Diff,
3516 boolean)</literal> delegated to
3517 <literal>assertXMLEqual</literal>, weakening the
3518 assertion.</listitem>
3519
3520 <listitem>Under certain circumstances the reported XPath
3521 expressions for nodes that showed differences were wrong.
3522 XMLUnit could lose the root element or erroneously append an
3523 extra attribute name. Issues <ulink
3524 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1047364&amp;group_id=23187&amp;atid=377768">1047364</ulink>
3525 and <ulink url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1027863&amp;group_id=23187&amp;atid=377770">1027863</ulink>.</listitem>
3526
3527 <listitem>
3528 <literal>TolerantSaxParser</literal>'s logic in
3529 <literal>characters</literal> was broken and could cause
3530 <literal>StringIndexOutOfBoundsException</literal>s.
3531 <ulink
3532 url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1150234&amp;group_id=23187&amp;atid=377768">Issue 1150234</ulink>.</listitem>
3533 </itemizedlist>
3534 </section>
3535 </section>
3536
3537 <section id="Changes 1.2">
3538 <title>Changes from XMLUnit 1.1 to 1.2</title>
3539
3540 <section id="Breaking Changes 1.2">
3541 <title>Breaking Changes</title>
3542
3543 <itemizedlist>
3544 <listitem>
3545 If XMLUnit detects that it cannot match a certain node
3546 (i.e. it encounters
3547 a <literal>CHILD_NODE_NOT_FOUND</literal>
3548 kind of difference) the XPath for the "missing" node will
3549 be null. It used to be some random XPath of a different node.
3550 </listitem>
3551
3552 <listitem>
3553 <literal>XMLUnit.setIgnoreDiffBetweenTextAndCDATA</literal>
3554 now also
3555 sets <literal>DocumentBuilderFactory.setCoalescing</literal>.
3556 This has been done so that whitespace differences can be
3557 resolved according to the corresponding flags even in the
3558 presence of CDATA
3559 sections. <ulink href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1903923&amp;group_id=23187&amp;atid=377768">Issue
3560 1903923</ulink>.</listitem>
3561
3562 <listitem>
3563 Two protected methods
3564 in <literal>SimpleXPathEngine</literal> (which you
3565 shouldn't extend anyway) have added XpathException to
3566 their throws list.
3567 </listitem>
3568 </itemizedlist>
3569 </section>
3570
3571 <section id="New Features 1.2">
3572 <title>New Features</title>
3573
3574 <itemizedlist>
3575 <listitem>The <literal>SAXParserFactory</literal> used
3576 by <literal>Validator</literal> can now be configured
3577 completely. <ulink href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1903928&amp;group_id=23187&amp;atid=377771">Issue
3578 1903928</ulink>.</listitem>
3579
3580 <listitem>A new
3581 class <literal>org.custommonkey.xmlunit.jaxp13.Validator</literal>
3582 can be used to validate schema definitions and schema
3583 instances using the <literal>javax.xml.validation</literal>
3584 package of JAXP 1.3. Depending on your JAXP implementation
3585 this may allow you to validate documents against schema
3586 definitions written in RELAX NG or other schema languages in
3587 addition to W3C XML Schema. See
3588 <xref linkend="JAXP 1.3 Validation"/> for details.</listitem>
3589
3590 <listitem><literal>DifferenceListener</literal> can now
3591 "upgrade" recoverable differences to non-recoverable by
3592 returning <literal>RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT</literal>
3593 in the <literal>differenceFound</literal>
3594 method. <ulink url="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1854284&amp;group_id=23187&amp;atid=377771">Issue
3595 1854284</ulink>.</listitem>
3596
3597 <listitem>A new callback
3598 interface <literal>MatchTracker</literal> is now notified on
3599 successful matches of Nodes. For more details see
3600 <xref linkend="MatchTracker"/>. <ulink url="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1860491&amp;group_id=23187&amp;atid=377771">Issue
3601 1860491</ulink>.</listitem>
3602
3603 <listitem>It is now possible to have more control over
3604 whether the parser expand entity references or not by
3605 using <literal>XMLUnit.setExpandEntityReferences</literal>,
3606 see <xref linkend="Entity Reference
3607 Expansion"/>. <ulink href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1877458&amp;group_id=23187&amp;atid=377771">Issue
3608 1877458</ulink>.</listitem>
3609
3610 <listitem>New examples have been added:
3611 <itemizedlist>
3612 <listitem><literal>RecursiveElementNameAndTextQualifier</literal>
3613 - a more flexible <literal>ElementQualifier</literal>
3614 that fills the same need as
3615 <literal>MultiLevelElementNameAndTextQualifier</literal>
3616 See
3617 <xref linkend="RecursiveElementNameAndTextQualifier"/>
3618 for more details.</listitem>
3619
3620 <listitem><literal>CaseInsensitiveDifferenceListener</literal>
3621 a - <literal>DifferenceListener</literal> that ignores
3622 case when comparing texts.</listitem>
3623
3624 <listitem><literal>FloatingPointTolerantDifferenceListener</literal>
3625 a - <literal>DifferenceListener</literal> that tries
3626 to parse texts as floating point numbers and compares
3627 them using a configurable tolerance.</listitem>
3628 </itemizedlist>
3629 </listitem>
3630 </itemizedlist>
3631 </section>
3632
3633 <section id="Bugfixes 1.2">
3634 <title>Important Bug Fixes</title>
3635
3636 <itemizedlist>
3637 <listitem>
3638 If XMLUnit couldn't match nodes (i.e. it encountered
3639 a <literal>CHILD_NODE_NOT_FOUND</literal> kind of
3640 difference), the XPath expressions of the node details
3641 have been random. <ulink
3642 url="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1860681&amp;group_id=23187&amp;atid=377768">Issue 1860681</ulink>.
3643 </listitem>
3644 </itemizedlist>
3645 </section>
3646 </section>
3647
3648 <section id="Changes 1.3">
3649 <title>Changes from XMLUnit 1.2 to 1.3</title>
3650
3651 <section id="Breaking Changes 1.3">
3652 <title>Breaking Changes</title>
3653
3654 <!--itemizedlist>
3655 </itemizedlist-->
3656 </section>
3657
3658 <section id="New Features 1.3">
3659 <title>New Features</title>
3660
3661 <itemizedlist>
3662 <listitem>
3663 If XMLUnit doesn't find a matching Element for a control
3664 Element, it will match it against the first unmatched test
3665 Element (if there is one) instead of creating
3666 a <literal>CHILD_NODE_NOT_FOUND</literal> Difference.
3667 There now is a new configuration
3668 option <literal>compareUnmatched</literal> in
3669 the <literal>XMLUnit</literal> class that can be used to
3670 turn off this behavior - as a result
3671 two <literal>CHILD_NODE_NOT_FOUND</literal> Differences
3672 (one for the unmatched control Element and one for an
3673 unmatched test Element) will be created instead of a
3674 single Difference comparing the two likely unrelated
3675 nodes. See <xref linkend="Comparison of Unmatched
3676 Elements"/>.
3677 <ulink
3678 url="https://sourceforge.net/tracker/?func=detail&amp;aid=2758280&amp;group_id=23187&amp;atid=377768">Issue 2758280</ulink>.
3679 </listitem>
3680 </itemizedlist>
3681 </section>
3682
3683 <section id="Bugfixes 1.3">
3684 <title>Important Bug Fixes</title>
3685
3686 <itemizedlist>
3687 <listitem>
3688 If XMLUnit couldn't match attributes (i.e. it encountered
3689 a <literal>ATTR_NAME_NOT_FOUND_ID</literal> kind of
3690 difference), the XPath expressions of the node details
3691 have been random. <ulink
3692 url="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=2386807&amp;group_id=23187&amp;atid=377768">Issue 2386807</ulink>.
3693 </listitem>
3694 <listitem>
3695 In some cases XMLUnit matched test nodes to multiple
3696 control nodes and then created a "missing child"
3697 difference for remaining test nodes even though they would
3698 have been valid targets for control node matches as well.
3699 <ulink url="https://sourceforge.net/tracker/?func=detail&amp;aid=2807167&amp;group_id=23187&amp;atid=377768">Issue 2807167</ulink>.
3700 </listitem>
3701 </itemizedlist>
3702 </section>
3703 </section>
3704
3705 <section id="Changes 1.4">
3706 <title>Changes from XMLUnit 1.3 to 1.4</title>
3707
3708 <section id="Breaking Changes 1.4">
3709 <title>Breaking Changes</title>
3710
3711 <!--itemizedlist>
3712 </itemizedlist-->
3713 </section>
3714
3715 <section id="New Features 1.4">
3716 <title>New Features</title>
3717
3718 <itemizedlist>
3719 <listitem>
3720 xsi:type attributes now have their value interpreted as a
3721 QName and will compare as identical if their namespace URI
3722 and local names match even if they use different
3723 prefixes. <ulink url="https://sourceforge.net/tracker/?func=detail&amp;aid=3602981&amp;group_id=23187&amp;atid=377771">Issue 3602981</ulink>
3724 </listitem>
3725 </itemizedlist>
3726 </section>
3727
3728 <section id="Bugfixes 1.4">
3729 <title>Important Bug Fixes</title>
3730
3731 <itemizedlist>
3732 <listitem>
3733 <literal>XMLTestCase</literal>'s and <literal>XMLAssert</literal>'s
3734 <literal>assertXpathsEqual</literal> methods threw an
3735 exception when at least one XPath matched an attribute. <ulink
3736 url="https://sourceforge.net/tracker/?func=detail&amp;aid=3290264&amp;group_id=23187&amp;atid=377768">Issue 377768</ulink>.
3737 </listitem>
3738
3739 <listitem>
3740 <literal>FloatingPointTolerantDifferenceListener</literal>
3741 expected numbers to differ by less than the given
3742 tolerance rather than "less or equal" than as the docs said.
3743 <ulink
3744 href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=3593368&amp;group_id=23187&amp;atid=377768">Issue
3745 3593368</ulink>
3746 </listitem>
3747 </itemizedlist>
3748 </section>
3749 </section>
3750
3751 <section id="Changes 1.5">
3752 <title>Changes from XMLUnit 1.4 to 1.5</title>
3753
3754 <section id="Breaking Changes 1.5">
3755 <title>Breaking Changes</title>
3756
3757 <itemizedlist>
3758 <listitem>
3759 If one node in the comparison has children while the other
3760 one has not, XMLUnit 1.5 will signal a
3761 <literal>CHILD_NODELIST_LENGTH</literal> difference and
3762 <literal>CHILD_NODE_NOT_FOUND</literal>
3763 differences for each child node of the node that has
3764 children in addition to a <literal>HAS_CHILD_NODES</literal> difference.
3765 <ulink
3766 href="https://sourceforge.net/p/xmlunit/bugs/60/">Issue
3767 60</ulink>
3768 </listitem>
3769 </itemizedlist>
3770 </section>
3771
3772 <section id="New Features 1.5">
3773 <title>New Features</title>
3774
3775 <itemizedlist>
3776 <listitem>
3777 </listitem>
3778 </itemizedlist>
3779 </section>
3780
3781 <section id="Bugfixes 1.5">
3782 <title>Important Bug Fixes</title>
3783
3784 <itemizedlist>
3785 <listitem>
3786 <literal>RecursiveElementNameAndTextQualifier</literal> had some indices
3787 reversed leading to wrong results in some cases.
3788 <ulink
3789 href="https://sourceforge.net/p/xmlunit/bugs/62/">Issue
3790 62</ulink>
3791 </listitem>
3792 </itemizedlist>
3793 </section>
3794 </section>
3795
3796 <section id="Changes 1.6">
3797 <title>Changes from XMLUnit 1.5 to 1.6</title>
3798
3799 <section id="Breaking Changes 1.6">
3800 <title>Breaking Changes</title>
3801
3802 <itemizedlist>
3803 <listitem>
3804 In cases of <literal>ATTR_NAME_NOT_FOUND</literal> and
3805 <literal>CHILD_NODE_NOT_FOUND</literal> differences the
3806 value used to be the local name of the missing attribute
3807 or node. It will now be a Java5-QName-like
3808 <literal>{NS-URI}LOCAL-NAME</literal> string if the
3809 attribute or node belonged to an XML namespace.
3810 <ulink
3811 href="https://sourceforge.net/p/xmlunit/bugs/65/">Issue
3812 65</ulink>
3813 </listitem>
3814 </itemizedlist>
3815 </section>
3816
3817 <section id="New Features 1.6">
3818 <title>New Features</title>
3819
3820 <itemizedlist>
3821 <listitem>
3822 New <literal>assertXpathEvaluatesTo</literal>
3823 overloads in <literal>XMLAssert</literal> and a new
3824 <literal>QualifiedName</literal> class
3825 can be used to assert the stringified result of an XPath
3826 expression is actually a qualified name.
3827 <ulink
3828 href="https://sourceforge.net/p/xmlunit/feature-requests/25/">Feature
3829 Request 25</ulink>
3830 </listitem>
3831 </itemizedlist>
3832 </section>
3833
3834 <section id="Bugfixes 1.6">
3835 <title>Important Bug Fixes</title>
3836
3837 <itemizedlist>
3838 <listitem>
3839 The JAXP 1.3 based validator ignored
3840 <literal>xsi:namespaceLocation</literal> and
3841 <literal>xsi:noNamespaceLocation</literal> attributes.
3842 They will now be used if you don't specify any sources at
3843 all, but are still ignored if you
3844 specify any schema sources - since this is the way
3845 <literal>javax.xml.validation</literal> works.
3846 <ulink
3847 href="https://sourceforge.net/p/xmlunit/bugs/64/">Issue
3848 64</ulink>
3849 </listitem>
3850 <listitem>
3851 When an attribute cannot be found (a
3852 <literal>ATTR_NAME_NOT_FOUND</literal> difference) the
3853 XPath on the side where the attribute exists will now
3854 point to the attribute itself rather than its owning element.
3855 <ulink
3856 href="https://sourceforge.net/p/xmlunit/feature-requests/33/">Feature
3857 Request 33</ulink>
3858 </listitem>
3859 </itemizedlist>
3860 </section>
3861 </section>
3862
3863 </appendix>
3864
3865 </article>
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import java.io.File;
39 import java.io.FileReader;
40 import java.util.List;
41
42 import javax.xml.transform.stream.StreamSource;
43
44 import org.w3c.dom.Document;
45 import org.w3c.dom.Element;
46 import org.w3c.dom.Node;
47 import org.w3c.dom.Text;
48
49 import org.custommonkey.xmlunit.*;
50
51 /**
52 * All code snippets from the "A Tour of XMLUnit" section of the the
53 * User Guide.
54 */
55 public class ATourOfXMLUnit extends XMLTestCase {
56 public ATourOfXMLUnit(String name) {
57 super(name);
58 }
59
60 // never invoked
61 private void configure() {
62 System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
63 "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
64 System.setProperty("javax.xml.parsers.SAXParserFactory",
65 "org.apache.xerces.jaxp.SAXParserFactoryImpl");
66 System.setProperty("javax.xml.transform.TransformerFactory",
67 "org.apache.xalan.processor.TransformerFactoryImpl");
68 XMLUnit
69 .setControlParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
70 XMLUnit
71 .setTestParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
72 XMLUnit
73 .setSAXParserFactory("org.apache.xerces.jaxp.SAXParserFactoryImpl");
74 XMLUnit
75 .setTransformerFactory("org.apache.xalan.processor.TransformerFactoryImpl");
76 }
77
78 public void testForEquality() throws Exception {
79 String myControlXML = "<msg><uuid>0x00435A8C</uuid></msg>";
80 String myTestXML = "<msg><localId>2376</localId></msg>";
81 assertXMLEqual("Comparing test xml to control xml",
82 myControlXML, myTestXML);
83 }
84
85 public void testXMLIdentical()throws Exception {
86 String myControlXML =
87 "<struct><int>3</int><boolean>false</boolean></struct>";
88 String myTestXML =
89 "<struct><boolean>false</boolean><int>3</int></struct>";
90 Diff myDiff = new Diff(myControlXML, myTestXML);
91 assertTrue("XML similar " + myDiff.toString(),
92 myDiff.similar());
93 assertTrue("XML identical " + myDiff.toString(),
94 myDiff.identical());
95 }
96
97 public void testAllDifferences() throws Exception {
98 String myControlXML = "<news><item id=\"1\">War</item>"
99 + "<item id=\"2\">Plague</item>"
100 + "<item id=\"3\">Famine</item></news>";
101 String myTestXML = "<news><item id=\"1\">Peace</item>"
102 + "<item id=\"2\">Health</item>"
103 + "<item id=\"3\">Plenty</item></news>";
104 DetailedDiff myDiff = new DetailedDiff(new Diff(myControlXML,
105 myTestXML));
106 List allDifferences = myDiff.getAllDifferences();
107 assertEquals(myDiff.toString(), 2, allDifferences.size());
108 }
109
110 public void testCompareToSkeletonXML() throws Exception {
111 String myControlXML = "<location><street-address>22 any street</street-address><postcode>XY00 99Z</postcode></location>";
112 String myTestXML = "<location><street-address>20 east cheap</street-address><postcode>EC3M 1EB</postcode></location>";
113 DifferenceListener myDifferenceListener = new IgnoreTextAndAttributeValuesDifferenceListener();
114 Diff myDiff = new Diff(myControlXML, myTestXML);
115 myDiff.overrideDifferenceListener(myDifferenceListener);
116 assertTrue("test XML matches control skeleton XML",
117 myDiff.similar());
118 }
119
120 public void testRepeatedChildElements() throws Exception {
121 String myControlXML = "<suite>"
122 + "<test status=\"pass\">FirstTestCase</test>"
123 + "<test status=\"pass\">SecondTestCase</test></suite>";
124 String myTestXML = "<suite>"
125 + "<test status=\"pass\">SecondTestCase</test>"
126 + "<test status=\"pass\">FirstTestCase</test></suite>";
127 assertXMLNotEqual("Repeated child elements in different sequence order are not equal by default",
128 myControlXML, myTestXML);
129 Diff myDiff = new Diff(myControlXML, myTestXML);
130 myDiff.overrideElementQualifier(new ElementNameAndTextQualifier());
131 assertXMLEqual("But they are equal when an ElementQualifier controls which test element is compared with each control element",
132 myDiff, true);
133 }
134
135 public void testXSLTransformation() throws Exception {
136 String myInputXML = "...";
137 File myStylesheetFile = new File("...");
138 Transform myTransform = new Transform(myInputXML, myStylesheetFile);
139 String myExpectedOutputXML = "...";
140 Diff myDiff = new Diff(myExpectedOutputXML, myTransform);
141 assertTrue("XSL transformation worked as expected", myDiff.similar());
142 }
143
144 public void testAnotherXSLTransformation() throws Exception {
145 File myInputXMLFile = new File("...");
146 File myStylesheetFile = new File("...");
147 Transform myTransform = new Transform(
148 new StreamSource(myInputXMLFile),
149 new StreamSource(myStylesheetFile));
150 Document myExpectedOutputXML =
151 XMLUnit.buildDocument(XMLUnit.getControlParser(),
152 new FileReader("..."));
153 Diff myDiff = new Diff(myExpectedOutputXML,
154 myTransform.getResultDocument());
155 assertTrue("XSL transformation worked as expected", myDiff.similar());
156 }
157
158 public void testValidation() throws Exception {
159 XMLUnit.getTestDocumentBuilderFactory().setValidating(true);
160 // As the document is parsed it is validated against its referenced DTD
161 Document myTestDocument = XMLUnit.buildTestDocument("...");
162 String mySystemId = "...";
163 String myDTDUrl = new File("...").toURL().toExternalForm();
164 Validator myValidator = new Validator(myTestDocument, mySystemId,
165 myDTDUrl);
166 assertTrue("test document validates against unreferenced DTD",
167 myValidator.isValid());
168 }
169
170 public void testXPaths() throws Exception {
171 String mySolarSystemXML = "<solar-system>"
172 + "<planet name='Earth' position='3' supportsLife='yes'/>"
173 + "<planet name='Venus' position='4'/></solar-system>";
174 assertXpathExists("//planet[@name='Earth']", mySolarSystemXML);
175 assertXpathNotExists("//star[@name='alpha centauri']",
176 mySolarSystemXML);
177 assertXpathsEqual("//planet[@name='Earth']",
178 "//planet[@position='3']", mySolarSystemXML);
179 assertXpathsNotEqual("//planet[@name='Venus']",
180 "//planet[@supportsLife='yes']",
181 mySolarSystemXML);
182 }
183
184 public void testXPathValues() throws Exception {
185 String myJavaFlavours = "<java-flavours>"
186 + "<jvm current='some platforms'>1.1.x</jvm>"
187 + "<jvm current='no'>1.2.x</jvm>"
188 + "<jvm current='yes'>1.3.x</jvm>"
189 + "<jvm current='yes' latest='yes'>1.4.x</jvm></javaflavours>";
190 assertXpathEvaluatesTo("2", "count(//jvm[@current='yes'])",
191 myJavaFlavours);
192 assertXpathValuesEqual("//jvm[4]/@latest", "//jvm[4]/@current",
193 myJavaFlavours);
194 assertXpathValuesNotEqual("//jvm[2]/@current",
195 "//jvm[3]/@current", myJavaFlavours);
196 }
197
198 public void testXpathsInHTML() throws Exception {
199 String someBadlyFormedHTML = "<html><title>Ugh</title>"
200 + "<body><h1>Heading<ul>"
201 + "<li id='1'>Item One<li id='2'>Item Two";
202 TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder =
203 new TolerantSaxDocumentBuilder(XMLUnit.getTestParser());
204 HTMLDocumentBuilder htmlDocumentBuilder =
205 new HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
206 Document wellFormedDocument =
207 htmlDocumentBuilder.parse(someBadlyFormedHTML);
208 assertXpathEvaluatesTo("Item One", "/html/body//li[@id='1']",
209 wellFormedDocument);
210 }
211
212 public void testCountingNodeTester() throws Exception {
213 String testXML = "<fibonacci><val>1</val><val>2</val><val>3</val>"
214 + "<val>5</val><val>9</val></fibonacci>";
215 CountingNodeTester countingNodeTester = new CountingNodeTester(4);
216 assertNodeTestPasses(testXML, countingNodeTester, Node.TEXT_NODE);
217 }
218
219 public void testCustomNodeTester() throws Exception {
220 String testXML = "<fibonacci><val>1</val><val>2</val><val>3</val>"
221 + "<val>5</val><val>9</val></fibonacci>";
222 NodeTest nodeTest = new NodeTest(testXML);
223 assertNodeTestPasses(nodeTest, new FibonacciNodeTester(),
224 new short[] {Node.TEXT_NODE,
225 Node.ELEMENT_NODE},
226 true);
227 }
228
229 private class FibonacciNodeTester extends AbstractNodeTester {
230 private int nextVal = 1, lastVal = 1, priorVal = 0;
231
232 public void testText(Text text) throws NodeTestException {
233 int val = Integer.parseInt(text.getData());
234 if (nextVal != val) {
235 throw new NodeTestException("Incorrect value", text);
236 }
237 nextVal = val + lastVal;
238 priorVal = lastVal;
239 lastVal = val;
240 }
241
242 public void testElement(Element element) throws NodeTestException {
243 String name = element.getLocalName();
244 if ("fibonacci".equals(name) || "val".equals(name)) {
245 return;
246 }
247 throw new NodeTestException("Unexpected element", element);
248 }
249
250 public void noMoreNodes(NodeTest nodeTest) throws NodeTestException {
251 }
252 }
253 }
254
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import java.util.Arrays;
39 import java.util.List;
40
41 import org.custommonkey.xmlunit.*;
42 import org.w3c.dom.*;
43
44 /**
45 * Code from "Comparing Pieces of XML" section of User's Guide
46 */
47 public class ComparingPiecesOfXML extends XMLTestCase {
48
49 class MyDifferenceListener implements DifferenceListener {
50 private boolean calledFlag = false;
51 public boolean called() { return calledFlag; }
52
53 public int differenceFound(Difference difference) {
54 calledFlag = true;
55 return RETURN_ACCEPT_DIFFERENCE;
56 }
57
58 public void skippedComparison(Node control, Node test) {
59 }
60 }
61
62 private void usingDifferenceEngineDirectly() {
63 ComparisonController myComparisonController = null;
64 Node controlNode = null;
65 Node testNode = null;
66 ElementQualifier myElementQualifier = null;
67
68 DifferenceEngine engine = new DifferenceEngine(myComparisonController);
69 MyDifferenceListener listener = new MyDifferenceListener();
70 engine.compare(controlNode, testNode, listener,
71 myElementQualifier);
72 System.err.println("There have been "
73 + (listener.called() ? "" : "no ")
74 + "differences.");
75 }
76
77 public class HaltOnNonRecoverable implements ComparisonController {
78 public boolean haltComparison(Difference afterDifference) {
79 return !afterDifference.isRecoverable();
80 }
81 }
82
83 public static class IgnoreDoctype implements DifferenceListener {
84 private static final int[] IGNORE = new int[] {
85 DifferenceConstants.HAS_DOCTYPE_DECLARATION_ID,
86 DifferenceConstants.DOCTYPE_NAME_ID,
87 DifferenceConstants.DOCTYPE_PUBLIC_ID_ID,
88 DifferenceConstants.DOCTYPE_SYSTEM_ID_ID
89 };
90
91 static {
92 Arrays.sort(IGNORE);
93 }
94
95 public int differenceFound(Difference difference) {
96 return Arrays.binarySearch(IGNORE, difference.getId()) >= 0
97 ? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
98 : RETURN_ACCEPT_DIFFERENCE;
99 }
100
101 public void skippedComparison(Node control, Node test) {
102 }
103 }
104
105 private void comparingTwoPiecesOfXMLUsingDiff() throws Exception {
106 Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
107 assertFalse(d.identical()); // CHILD_NODELIST_SEQUENCE Difference
108 assertTrue(d.similar());
109 }
110
111 private void FindingAllDifferencesUsingDetailedDiff() throws Exception {
112 Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
113 DetailedDiff dd = new DetailedDiff(d);
114 dd.overrideElementQualifier(null);
115 assertFalse(dd.similar());
116 List l = dd.getAllDifferences();
117 assertEquals(2, l.size()); // expexted <b/> but was <c/> and vice versa
118 }
119
120 private void junit3() throws Exception {
121 String CONTROL = null;
122 String TEST = null;
123 Diff d = new Diff(CONTROL, TEST);
124 assertTrue("expected pieces to be similar, " + d.toString(),
125 d.similar());
126 assertXMLEqual("expected pieces to be similar", CONTROL, TEST);
127 }
128 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import junit.framework.TestCase;
39
40 import org.custommonkey.xmlunit.*;
41 import org.w3c.dom.*;
42
43 /**
44 * Code from "DOM Tree Walking" section of User's Guide
45 */
46 public class DOMTreeWalking extends TestCase {
47
48 private String myXML = null;
49 static final String ATTRIBUTE_NAME = null;
50
51 private void AccessingAttributesInANodeTest() throws Exception {
52 NodeTest nt = new NodeTest(myXML);
53 NodeTester tester = new MyNodeTester();
54 nt.performTest(tester, Node.ELEMENT_NODE);
55 }
56
57 private void AccessingAttributesInANodeTestAbstractNodeTesterVersion() throws Exception {
58 NodeTest nt = new NodeTest(myXML);
59 NodeTester tester = new AbstractNodeTester() {
60 public void testElement(Element element) throws NodeTestException {
61 Attr attributeToTest = element.getAttributeNode(ATTRIBUTE_NAME);
62 }
63 };
64 nt.performTest(tester, Node.ELEMENT_NODE);
65 }
66
67 static class MyNodeTester implements NodeTester {
68 public void testNode(Node aNode, NodeTest test) {
69 Element anElement = (Element) aNode;
70 Attr attributeToTest = anElement.getAttributeNode(ATTRIBUTE_NAME);
71 }
72
73 public void noMoreNodes(NodeTest test) {}
74 }
75 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import java.io.*;
39 import org.custommonkey.xmlunit.*;
40 import org.xml.sax.*;
41
42 /**
43 * Code from "Validating XML Documents" section of User's Guide
44 */
45 public class ValidatingXMLDocuments {
46
47 private String myXmlDocument = null;
48 private String myDTD = null;
49
50 private void ValidatingAgainstTheDTDDefinedInDOCTYPE() throws Exception {
51 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
52 Validator v = new Validator(is);
53 boolean isValid = v.isValid();
54 }
55
56 private void ValidatingAPieceOfXMLThatDoesntContainADOCTYPE() throws Exception {
57 String myPublicId = null;
58
59 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
60 Validator v = new Validator(is,
61 (new File(myDTD)).toURI().toURL().toString(),
62 myPublicId);
63 boolean isValid = v.isValid();
64 }
65
66 private void ValidatingAgainstALocalDTD() throws Exception {
67 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
68 Validator v = new Validator(is,
69 (new File(myDTD)).toURI().toURL().toString());
70 boolean isValid = v.isValid();
71 }
72
73 private void ValidatingAgainstDTDUsingApachesXMLResolverAndAXMLCatalog() throws Exception {
74 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
75 XMLUnit.setControlEntityResolver(new CatalogResolver());
76 Validator v = new Validator(is);
77 boolean isValid = v.isValid();
78 }
79
80 private void ValidatingAgainstALocalXMLSchema() throws Exception {
81 String myXmlSchemaFile = null;
82
83 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
84 Validator v = new Validator(is);
85 v.useXMLSchema(true);
86 v.setJAXP12SchemaSource(new File(myXmlSchemaFile));
87 boolean isValid = v.isValid();
88 }
89
90 private static class CatalogResolver implements EntityResolver {
91 public InputSource resolveEntity(String p, String s) {
92 return null;
93 }
94 }
95 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import java.util.HashMap;
39 import junit.framework.Assert;
40 import junit.framework.TestCase;
41
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.NodeList;
45 import org.custommonkey.xmlunit.*;
46
47 /**
48 * Code from "XPath Tests" section of User's Guide
49 */
50 public class XPathTests extends TestCase {
51
52 private void MatchingAnXPathSelectionAgainstARegularExpression() throws Exception {
53 Document doc = null;
54 String regex = null;
55 String xpath = null;
56 String message = null;
57
58 XpathEngine engine = XMLUnit.newXpathEngine();
59 String value = engine.evaluate(xpath, doc);
60 Assert.assertTrue(message, value.matches(regex));
61 }
62
63 private void UsingNamespacesInXPathTests() throws Exception {
64 String testDoc = "<t:test xmlns:t=\"urn:foo\"><t:bar/></t:test>";
65 Document d = XMLUnit.buildControlDocument(testDoc);
66 HashMap m = new HashMap();
67 m.put("foo", "urn:foo");
68
69 NamespaceContext ctx = new SimpleNamespaceContext(m);
70 XpathEngine engine = XMLUnit.newXpathEngine();
71 engine.setNamespaceContext(ctx);
72
73 NodeList l = engine.getMatchingNodes("//foo:bar", d);
74 assertEquals(1, l.getLength());
75 assertEquals(Node.ELEMENT_NODE, l.item(0).getNodeType());
76 }
77
78 }
0 <?xml version="1.0"?>
1 <element name="Book" ns="http://www.publishing.org"
2 xmlns="http://relaxng.org/ns/structure/1.0">
3 <element name="Title"><text/></element>
4 <oneOrMore>
5 <element name="Author"><text/></element>
6 </oneOrMore>
7 <element name="Date"><text/></element>
8 <element name="ISBN"><text/></element>
9 <element name="Publisher"><text/></element>
10 </element>
0 namespace b = "http://www.publishing.org"
1
2 element b:Book {
3 element b:Title { text },
4 element b:Author { text }+,
5 element b:Date { text },
6 element b:ISBN { text },
7 element b:Publisher { text }
8 }
0 <?xml version="1.0"?>
1 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
2 targetNamespace="http://www.publishing.org"
3 xmlns="http://www.publishing.org"
4 version="1.0"
5 elementFormDefault="qualified">
6
7 <xsd:element name="Book" type="BookType"/>
8
9 <xsd:complexType name="BookType">
10 <xsd:sequence>
11 <xsd:element name="Title" type="xsd:string" minOccurs="1" maxOccurs="1"/>
12 <xsd:element name="Author" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
13 <xsd:element name="Date" type="xsd:string" minOccurs="1" maxOccurs="1"/>
14 <xsd:element name="ISBN" type="xsd:string" minOccurs="1" maxOccurs="1"/>
15 <xsd:element name="Publisher" type="xsd:string" minOccurs="1" maxOccurs="1"/>
16 </xsd:sequence>
17 </xsd:complexType>
18 </xsd:schema>
19
0 <?xml version="1.0"?>
1 <foo:schema xmlns:foo="http://www.w3.org/2001/XMLSchema"
2 targetNamespace="http://www.publishing.org"
3 xmlns="http://www.publishing.org"
4 version="1.0"
5 elementFormDefault="qualified">
6
7 <foo:element name="Book" type="BookType"/>
8
9 <foo:complexType name="BookType">
10 <foo:sequence>
11 <foo:element name="Title" type="foo:string" minOccurs="1" maxOccurs="1"/>
12 <foo:element name="Author" type="foo:string" minOccurs="1" maxOccurs="unbounded"/>
13 <foo:element name="Date" type="foo:string" minOccurs="1" maxOccurs="1"/>
14 <foo:element name="ISBN" type="foo:string" minOccurs="1" maxOccurs="1"/>
15 <foo:element name="Publisher" type="foo:string" minOccurs="1" maxOccurs="1"/>
16 </foo:sequence>
17 </foo:complexType>
18 </foo:schema>
19
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Book xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" xmlns="http://www.publishing.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.publishing.org tests/etc/Book.xsd">
2 <Title>Chicken Soup for the Soul</Title>
3 <Author>Jack Canfield</Author>
4 <Author>Mark Victor Hansen</Author>
5 <Date>1993</Date>
6 <ISBN>1-55874-262-X</ISBN>
7 <Publisher>Health Communications, Inc.</Publisher>
8 </Book>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Book xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" xmlns="http://www.publishing.org">
2 <Title>Chicken Soup for the Soul</Title>
3 <Author>Jack Canfield</Author>
4 <Author>Mark Victor Hansen</Author>
5 <Date>1993</Date>
6 <ISBN>1-55874-262-X</ISBN>
7 <Publisher>Health Communications, Inc.</Publisher>
8 </Book>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Book xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" xmlns="http://www.publishing.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.publishing.org Book.xsd">
2 <Title>Chicken Soup for the Soul</Title>
3 <Author>Jack Canfield</Author>
4 <Author>Mark Victor Hansen</Author>
5 <Date>1993</Date>
6 <ISBN>1-55874-262-X</ISBN>
7 <Publisher>Health Communications, Inc.</Publisher>
8 </Book>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Book xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" xmlns="http://www.publishing.org">
2 <Title>Chicken Soup for the Soul</Title>
3 <Author>Jack Canfield</Author>
4 <Author>Mark Victor Hansen</Author>
5 <Date>1993</Date>
6 <ISBN>1-55874-262-X</ISBN>
7 <goat>Billy</goat>
8 <Publisher>Health Communications, Inc.</Publisher>
9 </Book>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
2 <xsl:output method="xml" version="1.0" encoding="UTF-8"/>
3
4 <xsl:template match="animal">
5 <xsl:param name="whatAnimal"><xsl:value-of select="."/></xsl:param>
6 <xsl:element name="{$whatAnimal}"/>
7 </xsl:template>
8
9 </xsl:stylesheet>
0 <?xml version="1.0"?>
1 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
2 targetNamespace="http://www.publishing.org"
3 xmlns="http://www.publishing.org"
4 version="1.0"
5 elementFormDefault="qualified">
6
7 <xsd:element name="Book" type="BookType"/>
8
9 <xsd:complexType name="BookType">
10 <xsd:element name="Title" type="xsd:string" minOccurs="1" maxOccurs="1"/>
11 <xsd:element name="Author" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
12 <xsd:element name="Date" type="xsd:string" minOccurs="1" maxOccurs="1"/>
13 <xsd:element name="ISBN" type="xsd:string" minOccurs="1" maxOccurs="1"/>
14 </xsd:complexType>
15 </xsd:schema>
16
0 <?xml version="1.0" encoding="ISO-8859-1"?>
1 <DaoEreigDossier and_beschr="" op_steu_art="1" erdo_nr="5004299" ermd_lfnr="1" fall_ztlg_dat="2002-07-08" mutn_zpkt_cls="2002-07-08-12.07.36.364145">
2 <han_weisg_liste length="0"/>
3 <autom_termin_liste length="4">
4 <NvpListe length="5">
5 <DaoNvp attr_name="OBJ_ID" attr_value_txt="UUID5e891b:eee984ee59:-7ade" attr_value_num="0"/>
6 <DaoNvp attr_name="ATTR_WERT" attr_value_txt="2" attr_value_num="0"/>
7 <DaoNvp attr_name="TERMIN_ID" attr_value_txt="2002-07-08-12.07.07.403665" attr_value_num="0"/>
8 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="1"/>
9 <DaoNvp attr_name="ATTR_NAME" attr_value_txt="kontaktMassnahmen" attr_value_num="0"/>
10 </NvpListe>
11 <NvpListe length="5">
12 <DaoNvp attr_name="OBJ_ID" attr_value_txt="UUID5e891b:eee984ee59:-7ade" attr_value_num="0"/>
13 <DaoNvp attr_name="ATTR_WERT" attr_value_txt="1" attr_value_num="0"/>
14 <DaoNvp attr_name="TERMIN_ID" attr_value_txt="2002-07-08-12.06.48.997697" attr_value_num="0"/>
15 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="1"/>
16 <DaoNvp attr_name="ATTR_NAME" attr_value_txt="unfallprotokollJN" attr_value_num="0"/>
17 </NvpListe>
18 <NvpListe length="5">
19 <DaoNvp attr_name="OBJ_ID" attr_value_txt="UUID5e891b:eee984ee59:-7aab" attr_value_num="0"/>
20 <DaoNvp attr_name="ATTR_WERT" attr_value_txt="1" attr_value_num="0"/>
21 <DaoNvp attr_name="TERMIN_ID" attr_value_txt="2002-07-08-12.06.58.208799" attr_value_num="0"/>
22 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="1"/>
23 <DaoNvp attr_name="ATTR_NAME" attr_value_txt="teleclaimsFallJN" attr_value_num="0"/>
24 </NvpListe>
25 <NvpListe length="4">
26 <DaoNvp attr_name="OBJ_ID" attr_value_txt="UUID5e891b:eee984ee59:-7ac8" attr_value_num="0"/>
27 <DaoNvp attr_name="TERMIN_ID" attr_value_txt="2002-07-08-12.07.15.551168" attr_value_num="0"/>
28 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="1"/>
29 <DaoNvp attr_name="ATTR_NAME" attr_value_txt="VonDeckungspruefunggeneriert" attr_value_num="0"/>
30 </NvpListe>
31 </autom_termin_liste>
32 <ereig_mldg_liste length="1">
33 <DaoEreigMldg erhg_lbeschr="dumm gegangen" kntkt_ma_beschr="massnahme überflüssig" kntkt_ihalt_beschr="inhalt des kontaktes" schufra_bgrdg="dämlicher Idiot" sc_urs_beschr="" rettg_vsuch_beschr="" wind_gschw_grd="" sc_urs_beschr_kbsc="" aufgbr_bdiengpers="" auftr_beschr="" pstund_bgrdg="" rng_erwartt_beschr="" sc_dat_von="2002-07-01" sc_dat_bis="0001-01-01" poliz_rapp_dat="2002-07-05" sc_zeit_von="00.00.00" sc_zeit_bis="00.00.00" erstg_zpkt="2002-07-08-11.59.00.000043">
34 <so_ma_liste length="0"/>
35 <mldg_zus_mfk_liste length="1">
36 <DaoMldgZusMfk bvm_vdacht_beschr="" deckg_eshd_bgrdg="deckung" haftg_eshd_bgrdg="" regr_eshd_bgrdg="regress" meld_dat_wildh="0001-01-01" gueab_pol="2001-09-25" abl_dat_pol="2004-12-31" anulg_dat="0001-01-01">
37 <deckg_pruefg_liste length="3">
38 <NvpListe length="5">
39 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
40 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
41 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ab8" attr_value_num="0"/>
42 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="145"/>
43 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="0"/>
44 </NvpListe>
45 <NvpListe length="5">
46 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
47 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
48 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ac7" attr_value_num="0"/>
49 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="200"/>
50 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="0"/>
51 </NvpListe>
52 <NvpListe length="5">
53 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
54 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
55 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ac5" attr_value_num="0"/>
56 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="23"/>
57 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="1"/>
58 </NvpListe>
59 </deckg_pruefg_liste>
60 <part_rol_liste length="2">
61 <DaoPartRol part_rol_cdcls="200" adr_nr="27635" part_id="-1"/>
62 <DaoPartRol part_rol_cdcls="300" adr_nr="27635" part_id="-1"/>
63 </part_rol_liste>
64 <nvp_liste length="15">
65 <DaoNvp attr_name="DECKG_ESHD_CDCLS" attr_value_txt="" attr_value_num="1"/>
66 <DaoNvp attr_name="KF_FREIW_LSTG" attr_value_txt="" attr_value_num="0"/>
67 <DaoNvp attr_name="SC_ART_CDCLS" attr_value_txt="" attr_value_num="1"/>
68 <DaoNvp attr_name="KF_BVM_VDACHT_MANU" attr_value_txt="" attr_value_num="0"/>
69 <DaoNvp attr_name="V_BR_CDU_SC" attr_value_txt="" attr_value_num="99020"/>
70 <DaoNvp attr_name="OBJ_ID_MZ_MF_KASKO" attr_value_txt="UUID5e891b:eee984ee59:-7ace" attr_value_num="0"/>
71 <DaoNvp attr_name="ANGB_ERGZG" attr_value_txt="GE 516065/PW" attr_value_num="0"/>
72 <DaoNvp attr_name="REGR_ESHD_CDCLS" attr_value_txt="" attr_value_num="2"/>
73 <DaoNvp attr_name="KZ_VTRG_ZUST_PROVI" attr_value_txt="" attr_value_num="0"/>
74 <DaoNvp attr_name="OBJ_ID_DECKG_ESHD" attr_value_txt="UUID5e891b:eee984ee59:-7ab3" attr_value_num="0"/>
75 <DaoNvp attr_name="OBJ_ID_REGR_ESHD" attr_value_txt="UUID5e891b:eee984ee59:-7ab2" attr_value_num="0"/>
76 <DaoNvp attr_name="POL_NR" attr_value_txt="" attr_value_num="16516065"/>
77 <DaoNvp attr_name="VTRG_BR_CDU" attr_value_txt="" attr_value_num="99000"/>
78 <DaoNvp attr_name="VTRG_STAT_CDCLS" attr_value_txt="" attr_value_num="1"/>
79 <DaoNvp attr_name="OBJ_ID_BVM_VDACHT" attr_value_txt="UUID5e891b:eee984ee59:-7ab1" attr_value_num="0"/>
80 </nvp_liste>
81 </DaoMldgZusMfk>
82 </mldg_zus_mfk_liste>
83 <mldg_zus_mfh_liste length="1">
84 <DaoMldgZusMfh bvm_vdacht_beschr="" deckg_eshd_bgrdg="deckung 2" haftg_eshd_bgrdg="haftung 2" regr_eshd_bgrdg="regress 2" gueab_pol="2001-09-25" abl_dat_pol="2004-12-31" anulg_dat="0001-01-01">
85 <deckg_pruefg_liste length="3">
86 <NvpListe length="5">
87 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
88 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
89 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ab9" attr_value_num="0"/>
90 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="145"/>
91 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="0"/>
92 </NvpListe>
93 <NvpListe length="5">
94 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
95 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
96 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ac8" attr_value_num="0"/>
97 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="200"/>
98 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="1"/>
99 </NvpListe>
100 <NvpListe length="5">
101 <DaoNvp attr_name="KF_TERMIN_GESPERRT" attr_value_txt="" attr_value_num="0"/>
102 <DaoNvp attr_name="KF_TERMIN_AUSGLST" attr_value_txt="" attr_value_num="0"/>
103 <DaoNvp attr_name="OBJ_ID_DECKG_PRUEF" attr_value_txt="UUID5e891b:eee984ee59:-7ac6" attr_value_num="0"/>
104 <DaoNvp attr_name="TERMIN_ART_CDCLS" attr_value_txt="" attr_value_num="23"/>
105 <DaoNvp attr_name="KF_TERMIN_SETZ" attr_value_txt="" attr_value_num="0"/>
106 </NvpListe>
107 </deckg_pruefg_liste>
108 <part_rol_liste length="2">
109 <DaoPartRol part_rol_cdcls="200" adr_nr="30584" part_id="-1"/>
110 <DaoPartRol part_rol_cdcls="300" adr_nr="27635" part_id="-1"/>
111 </part_rol_liste>
112 <nvp_liste length="31">
113 <DaoNvp attr_name="BVI_ABWKLG" attr_value_txt="" attr_value_num="33"/>
114 <DaoNvp attr_name="POL_NR" attr_value_txt="" attr_value_num="16516065"/>
115 <DaoNvp attr_name="ANGB_ERGZG" attr_value_txt="GE 516065/PW" attr_value_num="0"/>
116 <DaoNvp attr_name="VTRG_STAT_CDCLS" attr_value_txt="" attr_value_num="1"/>
117 <DaoNvp attr_name="KZ_VTRG_ZUST_PROVI" attr_value_txt="" attr_value_num="0"/>
118 <DaoNvp attr_name="KF_FREIW_LSTG" attr_value_txt="" attr_value_num="0"/>
119 <DaoNvp attr_name="DECKG_ESHD_CDCLS" attr_value_txt="" attr_value_num="1"/>
120 <DaoNvp attr_name="OBJ_ID_HAFTG_ESHD" attr_value_txt="UUID5e891b:eee984ee59:-7ab4" attr_value_num="0"/>
121 <DaoNvp attr_name="BVI_SC_EREIG" attr_value_txt="" attr_value_num="0"/>
122 <DaoNvp attr_name="BVI_FZ_VN" attr_value_txt="" attr_value_num="8"/>
123 <DaoNvp attr_name="VTRG_BR_CDU" attr_value_txt="" attr_value_num="99000"/>
124 <DaoNvp attr_name="HAFTG_ESHD_CDCLS" attr_value_txt="" attr_value_num="1"/>
125 <DaoNvp attr_name="BVI_DATENLAGE" attr_value_txt="" attr_value_num="0"/>
126 <DaoNvp attr_name="OBJ_ID_REGR_ESHD" attr_value_txt="UUID5e891b:eee984ee59:-7ab6" attr_value_num="0"/>
127 <DaoNvp attr_name="REGR_ESHD_CDCLS" attr_value_txt="" attr_value_num="2"/>
128 <DaoNvp attr_name="KF_BVM_VDACHT_MANU" attr_value_txt="" attr_value_num="0"/>
129 <DaoNvp attr_name="BVI_PERS_VN" attr_value_txt="" attr_value_num="7"/>
130 <DaoNvp attr_name="BVI_PRUEFG" attr_value_txt="" attr_value_num="0"/>
131 <DaoNvp attr_name="BVI_PERS_ANSPRSTR" attr_value_txt="" attr_value_num="5"/>
132 <DaoNvp attr_name="OBJ_ID_MZ_MF_HAFT" attr_value_txt="UUID5e891b:eee984ee59:-7acf" attr_value_num="0"/>
133 <DaoNvp attr_name="BVI_LENKR_ANSPRSTR" attr_value_txt="" attr_value_num="17"/>
134 <DaoNvp attr_name="OBJ_ID_DECKG_ESHD" attr_value_txt="UUID5e891b:eee984ee59:-7ab7" attr_value_num="0"/>
135 <DaoNvp attr_name="BVI_KOMP" attr_value_txt="" attr_value_num="0"/>
136 <DaoNvp attr_name="V_BR_CDU_SC" attr_value_txt="" attr_value_num="99010"/>
137 <DaoNvp attr_name="OBJ_ID_BVM_VDACHT" attr_value_txt="UUID5e891b:eee984ee59:-7ab5" attr_value_num="0"/>
138 <DaoNvp attr_name="BVI_SC" attr_value_txt="" attr_value_num="0"/>
139 <DaoNvp attr_name="BVI_VTRG_VN" attr_value_txt="" attr_value_num="0"/>
140 <DaoNvp attr_name="OBJ_ID_BVM_RESULT" attr_value_txt="UUID5e891b:eee984ee59:-7aac" attr_value_num="0"/>
141 <DaoNvp attr_name="BVI_LENKR_VN" attr_value_txt="" attr_value_num="1"/>
142 <DaoNvp attr_name="BVI_FZ_ANSPRSTR" attr_value_txt="" attr_value_num="0"/>
143 <DaoNvp attr_name="KZ_BETRUG_VDACHT" attr_value_txt="" attr_value_num="0"/>
144 </nvp_liste>
145 </DaoMldgZusMfh>
146 </mldg_zus_mfh_liste>
147 <mldg_zus_mfu_liste length="0"/>
148 <mldg_zus_hausrat_liste length="0"/>
149 <mldg_zus_haph_liste length="0"/>
150 <mldg_zus_allg_haft_liste length="0"/>
151 <mldg_zus_Ueb_Br_liste length="0"/>
152 <part_rol_glob_liste length="6">
153 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="0001-01-01">
154 <nvp_liste length="3">
155 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID371566:eee983d86f:-5d88" attr_value_num="0"/>
156 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="300"/>
157 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="27635"/>
158 </nvp_liste>
159 </DaoPartRolGlob>
160 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="0001-01-01">
161 <nvp_liste length="3">
162 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID5e891b:eee984ee59:-7acd" attr_value_num="0"/>
163 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="200"/>
164 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="27635"/>
165 </nvp_liste>
166 </DaoPartRolGlob>
167 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="0001-01-01">
168 <nvp_liste length="3">
169 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID5e891b:eee984ee59:-7adf" attr_value_num="0"/>
170 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="100"/>
171 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="2780"/>
172 </nvp_liste>
173 </DaoPartRolGlob>
174 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="0001-01-01">
175 <nvp_liste length="3">
176 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID5e891b:eee984ee59:-7ad7" attr_value_num="0"/>
177 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="200"/>
178 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="30584"/>
179 </nvp_liste>
180 </DaoPartRolGlob>
181 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="0001-01-01">
182 <nvp_liste length="4">
183 <DaoNvp attr_name="PERS_AWAHL_CDCLS" attr_value_txt="" attr_value_num="3"/>
184 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID5e891b:eee984ee59:-7ad5" attr_value_num="0"/>
185 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="150"/>
186 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="2357"/>
187 </nvp_liste>
188 </DaoPartRolGlob>
189 <DaoPartRolGlob zus_beschr_fvr="" vursg_bgruendg="" austlg_dat_fueaw="1980-01-01">
190 <nvp_liste length="10">
191 <DaoNvp attr_name="KF_LENKR_VOLLM" attr_value_txt="" attr_value_num="1"/>
192 <DaoNvp attr_name="KF_VMIETG_GGBN" attr_value_txt="" attr_value_num="0"/>
193 <DaoNvp attr_name="KF_LENKR_IDNST_VN" attr_value_txt="" attr_value_num="1"/>
194 <DaoNvp attr_name="PERS_AWAHL_CDCLS" attr_value_txt="" attr_value_num="3"/>
195 <DaoNvp attr_name="KF_VWANDT_MIT_VN" attr_value_txt="" attr_value_num="0"/>
196 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="2357"/>
197 <DaoNvp attr_name="KF_LFUEAW_VORHD" attr_value_txt="" attr_value_num="0"/>
198 <DaoNvp attr_name="OBJ_ID_PART_ROL" attr_value_txt="UUID5e891b:eee984ee59:-7ad4" attr_value_num="0"/>
199 <DaoNvp attr_name="LAND_CDI_FUEAW" attr_value_txt="TAD" attr_value_num="0"/>
200 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="301"/>
201 </nvp_liste>
202 </DaoPartRolGlob>
203 </part_rol_glob_liste>
204 <sco_gbd_liste length="0"/>
205 <sco_pers_liste length="0"/>
206 <sco_fz_liste length="1">
207 <DaoScoFz zus_beschr_fvr="" bschaedg_ergzg="" sc_btrg_schaetz="0.0" exp_weitltg_dat="0001-01-01" reptr_mldg_dat="0001-01-01" bsichtg_dat="0001-01-01" beg_dat_reptr="0001-01-01" bsichtg_zeit="00.00.00">
208 <pvd_vmitlg_liste length="0"/>
209 <part_rol_liste length="1">
210 <DaoPartRol part_rol_cdcls="200" adr_nr="27635" part_id="-1"/>
211 </part_rol_liste>
212 <sca_fz_liste length="0"/>
213 <nvp_liste length="24">
214 <DaoNvp attr_name="INVSE" attr_value_txt="2001" attr_value_num="0"/>
215 <DaoNvp attr_name="ANZ_AIRBAG" attr_value_txt="" attr_value_num="0"/>
216 <DaoNvp attr_name="KSCHILD_NR" attr_value_txt="GE 516065" attr_value_num="0"/>
217 <DaoNvp attr_name="KZ_SCHEIBEN_GRAVUR" attr_value_txt="" attr_value_num="0"/>
218 <DaoNvp attr_name="STAMM_NR" attr_value_txt=" 165160654" attr_value_num="0"/>
219 <DaoNvp attr_name="KMST" attr_value_txt="" attr_value_num="0"/>
220 <DaoNvp attr_name="FZ_MARKE_TYP_CDTPR" attr_value_txt="" attr_value_num="1020624"/>
221 <DaoNvp attr_name="OBJ_ID_SO_FZ" attr_value_txt="UUID371566:eee983d86f:-592b" attr_value_num="0"/>
222 <DaoNvp attr_name="ANZ_SPLATZ" attr_value_txt="" attr_value_num="5"/>
223 <DaoNvp attr_name="LEERGEWICHT" attr_value_txt="" attr_value_num="1570"/>
224 <DaoNvp attr_name="WAEH_CDI_SCHAETZ" attr_value_txt="CHF" attr_value_num="0"/>
225 <DaoNvp attr_name="KZ_ABS" attr_value_txt="" attr_value_num="1"/>
226 <DaoNvp attr_name="KF_WV_VERS" attr_value_txt="" attr_value_num="1"/>
227 <DaoNvp attr_name="HUBRAUM" attr_value_txt="" attr_value_num="2290"/>
228 <DaoNvp attr_name="FZ_MARKE_TYP_BEZ" attr_value_txt="Saab 9-5 2.3T Aero" attr_value_num="0"/>
229 <DaoNvp attr_name="KF_LEASING" attr_value_txt="" attr_value_num="0"/>
230 <DaoNvp attr_name="KMST_AKTL" attr_value_txt="" attr_value_num="0"/>
231 <DaoNvp attr_name="KZ_DIEBS_SICHG" attr_value_txt="" attr_value_num="1"/>
232 <DaoNvp attr_name="FZ_ART_CDTPR" attr_value_txt="" attr_value_num="2"/>
233 <DaoNvp attr_name="FZ_WERT" attr_value_txt="" attr_value_num="59900"/>
234 <DaoNvp attr_name="OBJ_ID_BSCHAED_FZ" attr_value_txt="UUID5e891b:eee984ee59:-7acc" attr_value_num="0"/>
235 <DaoNvp attr_name="FZ_ZBHR_WEIT" attr_value_txt="" attr_value_num="0"/>
236 <DaoNvp attr_name="FZ_TYP_CDCLS" attr_value_txt="" attr_value_num="0"/>
237 <DaoNvp attr_name="FZ_KATLG_PREIS" attr_value_txt="" attr_value_num="59900"/>
238 </nvp_liste>
239 </DaoScoFz>
240 </sco_fz_liste>
241 <sco_fh_liste length="0"/>
242 <nvp_liste length="40">
243 <DaoNvp attr_name="VSIGN_VN_CDCLS" attr_value_txt="" attr_value_num="1"/>
244 <DaoNvp attr_name="LAND_CDI" attr_value_txt="CH" attr_value_num="0"/>
245 <DaoNvp attr_name="KZ_SC_DAT_ZRAUM" attr_value_txt="" attr_value_num="0"/>
246 <DaoNvp attr_name="STR" attr_value_txt="Gossauerstrasse 111" attr_value_num="0"/>
247 <DaoNvp attr_name="OBJ_ID_MZ_VKEHR" attr_value_txt="UUID5e891b:eee984ee59:-7abf" attr_value_num="0"/>
248 <DaoNvp attr_name="KZ_SC_ZEIT_ZRAUM" attr_value_txt="" attr_value_num="0"/>
249 <DaoNvp attr_name="KF_SVERHT_DUNKEL" attr_value_txt="" attr_value_num="1"/>
250 <DaoNvp attr_name="ORT" attr_value_txt="St. Gallen-Winkeln" attr_value_num="0"/>
251 <DaoNvp attr_name="KF_PERS_VLTZG" attr_value_txt="" attr_value_num="0"/>
252 <DaoNvp attr_name="KF_SVERHT_REGEN" attr_value_txt="" attr_value_num="1"/>
253 <DaoNvp attr_name="KZ_STR_ART_HSTR" attr_value_txt="" attr_value_num="1"/>
254 <DaoNvp attr_name="GSCHW_GP" attr_value_txt="66" attr_value_num="0"/>
255 <DaoNvp attr_name="VLTZG_GRAD_CDCLS" attr_value_txt="" attr_value_num="0"/>
256 <DaoNvp attr_name="TEL_POLIZ_POSTEN" attr_value_txt="000111222" attr_value_num="0"/>
257 <DaoNvp attr_name="OBJ_ID_ERMD" attr_value_txt="UUID5e891b:eee984ee59:-7ade" attr_value_num="0"/>
258 <DaoNvp attr_name="GSCHW_VN" attr_value_txt="55" attr_value_num="0"/>
259 <DaoNvp attr_name="ERHG_TYP_CDCLS" attr_value_txt="" attr_value_num="1"/>
260 <DaoNvp attr_name="KZ_STR_ART_WSTR" attr_value_txt="" attr_value_num="0"/>
261 <DaoNvp attr_name="KF_UNF_PROT_VORHD" attr_value_txt="" attr_value_num="1"/>
262 <DaoNvp attr_name="STR_VLAUF_GP_CDCLS" attr_value_txt="" attr_value_num="2"/>
263 <DaoNvp attr_name="OBJ_ID_POLIZ_RAPP" attr_value_txt="UUID5e891b:eee984ee59:-7abe" attr_value_num="0"/>
264 <DaoNvp attr_name="KZ_STR_ART_AUSORT" attr_value_txt="" attr_value_num="1"/>
265 <DaoNvp attr_name="KZ_SC_DAT_UGN" attr_value_txt="" attr_value_num="0"/>
266 <DaoNvp attr_name="KZ_STR_ART_AUTOB" attr_value_txt="" attr_value_num="0"/>
267 <DaoNvp attr_name="KF_VURSR_UBKNT" attr_value_txt="" attr_value_num="0"/>
268 <DaoNvp attr_name="KF_POLIZ_RAPP_VORH" attr_value_txt="" attr_value_num="1"/>
269 <DaoNvp attr_name="KZ_SC_ZEIT_UGN" attr_value_txt="" attr_value_num="0"/>
270 <DaoNvp attr_name="STR_VLAUF_VN_CDCLS" attr_value_txt="" attr_value_num="1"/>
271 <DaoNvp attr_name="KZ_STR_ART_NSTR" attr_value_txt="" attr_value_num="0"/>
272 <DaoNvp attr_name="NAME_POLIZ_BEAMT" attr_value_txt="P. Schmierler" attr_value_num="0"/>
273 <DaoNvp attr_name="ERHG_KBESCHR_CDCLS" attr_value_txt="" attr_value_num="5"/>
274 <DaoNvp attr_name="ERMD_TYP_CDCLS" attr_value_txt="" attr_value_num="1"/>
275 <DaoNvp attr_name="VSIGN_GP_CDCLS" attr_value_txt="" attr_value_num="2"/>
276 <DaoNvp attr_name="STR_ZUST_CDCLS" attr_value_txt="" attr_value_num="1"/>
277 <DaoNvp attr_name="POLIZ_POSTEN_BEZ" attr_value_txt="Kapo Autobahn" attr_value_num="0"/>
278 <DaoNvp attr_name="KF_H3_ANSPR_GGBN" attr_value_txt="" attr_value_num="1"/>
279 <DaoNvp attr_name="SCHUFRA_CDCLS" attr_value_txt="" attr_value_num="1"/>
280 <DaoNvp attr_name="KF_SVERHT_NEBEL" attr_value_txt="" attr_value_num="1"/>
281 <DaoNvp attr_name="PLZ" attr_value_txt="9000" attr_value_num="0"/>
282 <DaoNvp attr_name="KZ_STR_ART_INORT" attr_value_txt="" attr_value_num="1"/>
283 </nvp_liste>
284 </DaoEreigMldg>
285 </ereig_mldg_liste>
286 <kntkt_liste length="1">
287 <DaoKntkt kntkt_ma_beschr="" kntkt_ihalt_beschr="mutation" erstg_zpkt="2002-07-08-12.00.58.000701">
288 <aendrg_log_liste length="0"/>
289 <nvp_liste length="8">
290 <DaoNvp attr_name="MLD_KANAL_CDCLS" attr_value_txt="" attr_value_num="0"/>
291 <DaoNvp attr_name="MLDR_KNTKT_CDCLS" attr_value_txt="" attr_value_num="2"/>
292 <DaoNvp attr_name="KNTKT_ART_CDCLS" attr_value_txt="" attr_value_num="2"/>
293 <DaoNvp attr_name="KNTKT_MA_CDCLS" attr_value_txt="" attr_value_num="1"/>
294 <DaoNvp attr_name="USER_ID_ERSTR" attr_value_txt="C200891" attr_value_num="0"/>
295 <DaoNvp attr_name="OBJ_ID_ERMD" attr_value_txt="UUID5e891b:eee984ee59:-7ad2" attr_value_num="0"/>
296 <DaoNvp attr_name="PART_ROL_CDCLS" attr_value_txt="" attr_value_num="101"/>
297 <DaoNvp attr_name="ADR_NR" attr_value_txt="" attr_value_num="2780"/>
298 </nvp_liste>
299 </DaoKntkt>
300 </kntkt_liste>
301 <nvp_liste length="5">
302 <DaoNvp attr_name="KF_TC_FALL" attr_value_txt="" attr_value_num="1"/>
303 <DaoNvp attr_name="ERDO_STAT_CDCLS" attr_value_txt="" attr_value_num="1"/>
304 <DaoNvp attr_name="DIR_ZTLG_CDCLS" attr_value_txt="" attr_value_num="100"/>
305 <DaoNvp attr_name="OBJ_ID_ERDO" attr_value_txt="UUID5e891b:eee984ee59:-7ad1" attr_value_num="0"/>
306 <DaoNvp attr_name="OBJ_ID_FALL_ZTLG" attr_value_txt="UUID5e891b:eee984ee59:-7aab" attr_value_num="0"/>
307 </nvp_liste>
308 </DaoEreigDossier>
0 <?xml version="1.0"?>
1 <openSource xmlns="http://xmlunit.sourceforge.net/tests"
2 xmlns:ju="http://www.junit.org"
3 xmlns:ec="http://www.eclipse.org"
4 xmlns:ja="http://jakarta.apache.org">
5 <tool ju:version="3.8.1">jUnit</tool>
6 <tool ec:version="2.1">eclipse</tool>
7 <tool ja:version="1.5.1">ant</tool>
8 <tool ja:version="2.4">xalan</tool>
9 <tool ja:version="2.0.1">xerces</tool>
10 </openSource>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Book xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
2 xmlns="http://www.publishing.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.publishing.org tests/etc/Book.xsd">
3 <Title>Chicken Soup for the Soul</Title>
4 <Author>Jack Canfield</Author>
5 <Author>Mark Victor Hansen</Author>
6 <Date>1993</Date>
7 <ISBN>1-55874-262-X</ISBN>
8 </Book>
0 <html>
1 <head>
2 <title>Don't blame it on the...</title>
3 </head>
4 <body>
5 <ul>
6 <li>sunshine</li>
7 <li>moonlight</li>
8 <li>good times</li>
9 <li>boogie...?</li>
10 </ul>
11 </body>
12 </html>
(New empty file)
0 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml-stylesheet type="text/xsl" href="animal.xsl" ?>
2 <animal>
3 <furry>rabbit</furry>
4 </animal>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml-stylesheet href="animal.xsl" type="text/xsl"?>
2 <animal>
3 <hairy>caterpillar</hairy>
4 </animal>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml-stylesheet href="animal.xsl" type="text/xsl"?>
2 <animal><shaggy>dog</shaggy></animal>
0 <?xml version="1.0" encoding="ISO-8859-1"?>
1 <DaoEreigDossier and_beschr= "" op_steu_art= "1" erdo_nr= "5004299" ermd_lfnr= "1" fall_ztlg_dat= "2002-07-08" mutn_zpkt_cls= "2002-07-08-12.07.36.364145" >
2 <han_weisg_liste length= "0"></han_weisg_liste>
3 <autom_termin_liste length= "4"><NvpListe length= "5"><DaoNvp attr_name= "OBJ_ID" attr_value_txt= "UUID5e891b:eee984ee59:-7aab" attr_value_num= "0" >
4 </DaoNvp>
5 <DaoNvp attr_name= "ATTR_WERT" attr_value_txt= "1" attr_value_num= "0" >
6 </DaoNvp>
7 <DaoNvp attr_name= "TERMIN_ID" attr_value_txt= "2002-07-08-12.06.58.208799" attr_value_num= "0" >
8 </DaoNvp>
9 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "1" >
10 </DaoNvp>
11 <DaoNvp attr_name= "ATTR_NAME" attr_value_txt= "teleclaimsFallJN" attr_value_num= "0" >
12 </DaoNvp>
13 </NvpListe>
14 <NvpListe length= "4"><DaoNvp attr_name= "OBJ_ID" attr_value_txt= "UUID5e891b:eee984ee59:-7ac8" attr_value_num= "0" >
15 </DaoNvp>
16 <DaoNvp attr_name= "TERMIN_ID" attr_value_txt= "2002-07-08-12.07.15.551168" attr_value_num= "0" >
17 </DaoNvp>
18 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "1" >
19 </DaoNvp>
20 <DaoNvp attr_name= "ATTR_NAME" attr_value_txt= "VonDeckungspruefunggeneriert" attr_value_num= "0" >
21 </DaoNvp>
22 </NvpListe>
23 <NvpListe length= "5"><DaoNvp attr_name= "OBJ_ID" attr_value_txt= "UUID5e891b:eee984ee59:-7ade" attr_value_num= "0" >
24 </DaoNvp>
25 <DaoNvp attr_name= "ATTR_WERT" attr_value_txt= "2" attr_value_num= "0" >
26 </DaoNvp>
27 <DaoNvp attr_name= "TERMIN_ID" attr_value_txt= "2002-07-08-12.07.07.403665" attr_value_num= "0" >
28 </DaoNvp>
29 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "1" >
30 </DaoNvp>
31 <DaoNvp attr_name= "ATTR_NAME" attr_value_txt= "kontaktMassnahmen" attr_value_num= "0" >
32 </DaoNvp>
33 </NvpListe>
34 <NvpListe length= "5"><DaoNvp attr_name= "OBJ_ID" attr_value_txt= "UUID5e891b:eee984ee59:-7ade" attr_value_num= "0" >
35 </DaoNvp>
36 <DaoNvp attr_name= "ATTR_WERT" attr_value_txt= "1" attr_value_num= "0" >
37 </DaoNvp>
38 <DaoNvp attr_name= "TERMIN_ID" attr_value_txt= "2002-07-08-12.06.48.997697" attr_value_num= "0" >
39 </DaoNvp>
40 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "1" >
41 </DaoNvp>
42 <DaoNvp attr_name= "ATTR_NAME" attr_value_txt= "unfallprotokollJN" attr_value_num= "0" >
43 </DaoNvp>
44 </NvpListe>
45 </autom_termin_liste>
46 <ereig_mldg_liste length= "1"><DaoEreigMldg erhg_lbeschr= "dumm gegangen" kntkt_ma_beschr= "massnahme überflüssig" kntkt_ihalt_beschr= "inhalt des kontaktes" schufra_bgrdg= "dämlicher Idiot" sc_urs_beschr= "" rettg_vsuch_beschr= "" wind_gschw_grd= "" sc_urs_beschr_kbsc= "" aufgbr_bdiengpers= "" auftr_beschr= "" pstund_bgrdg= "" rng_erwartt_beschr= "" sc_dat_von= "2002-07-01" sc_dat_bis= "0001-01-01" poliz_rapp_dat= "2002-07-05" sc_zeit_von= "00.00.00" sc_zeit_bis= "00.00.00" erstg_zpkt= "2002-07-08-11.59.00.000043" >
47 <so_ma_liste length= "0"></so_ma_liste>
48 <mldg_zus_mfk_liste length= "1"><DaoMldgZusMfk bvm_vdacht_beschr= "" deckg_eshd_bgrdg= "deckung" haftg_eshd_bgrdg= "" regr_eshd_bgrdg= "regress" meld_dat_wildh= "0001-01-01" gueab_pol= "2001-09-25" abl_dat_pol= "2004-12-31" anulg_dat= "0001-01-01" >
49 <deckg_pruefg_liste length= "3"><NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
50 </DaoNvp>
51 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
52 </DaoNvp>
53 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ab8" attr_value_num= "0" >
54 </DaoNvp>
55 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "145" >
56 </DaoNvp>
57 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "0" >
58 </DaoNvp>
59 </NvpListe>
60 <NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
61 </DaoNvp>
62 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
63 </DaoNvp>
64 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ac7" attr_value_num= "0" >
65 </DaoNvp>
66 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "200" >
67 </DaoNvp>
68 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "0" >
69 </DaoNvp>
70 </NvpListe>
71 <NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
72 </DaoNvp>
73 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
74 </DaoNvp>
75 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ac5" attr_value_num= "0" >
76 </DaoNvp>
77 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "23" >
78 </DaoNvp>
79 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "1" >
80 </DaoNvp>
81 </NvpListe>
82 </deckg_pruefg_liste>
83 <part_rol_liste length= "2"><DaoPartRol part_rol_cdcls= "200" adr_nr= "27635" part_id= "-1" >
84 </DaoPartRol>
85 <DaoPartRol part_rol_cdcls= "300" adr_nr= "27635" part_id= "-1" >
86 </DaoPartRol>
87 </part_rol_liste>
88 <nvp_liste length= "15"><DaoNvp attr_name= "DECKG_ESHD_CDCLS" attr_value_txt= "" attr_value_num= "1" >
89 </DaoNvp>
90 <DaoNvp attr_name= "KF_FREIW_LSTG" attr_value_txt= "" attr_value_num= "0" >
91 </DaoNvp>
92 <DaoNvp attr_name= "SC_ART_CDCLS" attr_value_txt= "" attr_value_num= "1" >
93 </DaoNvp>
94 <DaoNvp attr_name= "KF_BVM_VDACHT_MANU" attr_value_txt= "" attr_value_num= "0" >
95 </DaoNvp>
96 <DaoNvp attr_name= "V_BR_CDU_SC" attr_value_txt= "" attr_value_num= "99020" >
97 </DaoNvp>
98 <DaoNvp attr_name= "OBJ_ID_MZ_MF_KASKO" attr_value_txt= "UUID5e891b:eee984ee59:-7ace" attr_value_num= "0" >
99 </DaoNvp>
100 <DaoNvp attr_name= "ANGB_ERGZG" attr_value_txt= "GE 516065/PW" attr_value_num= "0" >
101 </DaoNvp>
102 <DaoNvp attr_name= "REGR_ESHD_CDCLS" attr_value_txt= "" attr_value_num= "2" >
103 </DaoNvp>
104 <DaoNvp attr_name= "KZ_VTRG_ZUST_PROVI" attr_value_txt= "" attr_value_num= "0" >
105 </DaoNvp>
106 <DaoNvp attr_name= "OBJ_ID_DECKG_ESHD" attr_value_txt= "UUID5e891b:eee984ee59:-7ab3" attr_value_num= "0" >
107 </DaoNvp>
108 <DaoNvp attr_name= "OBJ_ID_REGR_ESHD" attr_value_txt= "UUID5e891b:eee984ee59:-7ab2" attr_value_num= "0" >
109 </DaoNvp>
110 <DaoNvp attr_name= "POL_NR" attr_value_txt= "" attr_value_num= "16516065" >
111 </DaoNvp>
112 <DaoNvp attr_name= "VTRG_BR_CDU" attr_value_txt= "" attr_value_num= "99000" >
113 </DaoNvp>
114 <DaoNvp attr_name= "VTRG_STAT_CDCLS" attr_value_txt= "" attr_value_num= "1" >
115 </DaoNvp>
116 <DaoNvp attr_name= "OBJ_ID_BVM_VDACHT" attr_value_txt= "UUID5e891b:eee984ee59:-7ab1" attr_value_num= "0" >
117 </DaoNvp>
118 </nvp_liste>
119 </DaoMldgZusMfk>
120 </mldg_zus_mfk_liste>
121 <mldg_zus_mfh_liste length= "1"><DaoMldgZusMfh bvm_vdacht_beschr= "" deckg_eshd_bgrdg= "deckung 2" haftg_eshd_bgrdg= "haftung 2" regr_eshd_bgrdg= "regress 2" gueab_pol= "2001-09-25" abl_dat_pol= "2004-12-31" anulg_dat= "0001-01-01" >
122 <deckg_pruefg_liste length= "3"><NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
123 </DaoNvp>
124 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
125 </DaoNvp>
126 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ab9" attr_value_num= "0" >
127 </DaoNvp>
128 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "145" >
129 </DaoNvp>
130 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "0" >
131 </DaoNvp>
132 </NvpListe>
133 <NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
134 </DaoNvp>
135 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
136 </DaoNvp>
137 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ac8" attr_value_num= "0" >
138 </DaoNvp>
139 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "200" >
140 </DaoNvp>
141 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "1" >
142 </DaoNvp>
143 </NvpListe>
144 <NvpListe length= "5"><DaoNvp attr_name= "KF_TERMIN_GESPERRT" attr_value_txt= "" attr_value_num= "0" >
145 </DaoNvp>
146 <DaoNvp attr_name= "KF_TERMIN_AUSGLST" attr_value_txt= "" attr_value_num= "0" >
147 </DaoNvp>
148 <DaoNvp attr_name= "OBJ_ID_DECKG_PRUEF" attr_value_txt= "UUID5e891b:eee984ee59:-7ac6" attr_value_num= "0" >
149 </DaoNvp>
150 <DaoNvp attr_name= "TERMIN_ART_CDCLS" attr_value_txt= "" attr_value_num= "23" >
151 </DaoNvp>
152 <DaoNvp attr_name= "KF_TERMIN_SETZ" attr_value_txt= "" attr_value_num= "0" >
153 </DaoNvp>
154 </NvpListe>
155 </deckg_pruefg_liste>
156 <part_rol_liste length= "2"><DaoPartRol part_rol_cdcls= "200" adr_nr= "30584" part_id= "-1" >
157 </DaoPartRol>
158 <DaoPartRol part_rol_cdcls= "300" adr_nr= "27635" part_id= "-1" >
159 </DaoPartRol>
160 </part_rol_liste>
161 <nvp_liste length= "31"><DaoNvp attr_name= "BVI_ABWKLG" attr_value_txt= "" attr_value_num= "33" >
162 </DaoNvp>
163 <DaoNvp attr_name= "POL_NR" attr_value_txt= "" attr_value_num= "16516065" >
164 </DaoNvp>
165 <DaoNvp attr_name= "ANGB_ERGZG" attr_value_txt= "GE 516065/PW" attr_value_num= "0" >
166 </DaoNvp>
167 <DaoNvp attr_name= "VTRG_STAT_CDCLS" attr_value_txt= "" attr_value_num= "1" >
168 </DaoNvp>
169 <DaoNvp attr_name= "KZ_VTRG_ZUST_PROVI" attr_value_txt= "" attr_value_num= "0" >
170 </DaoNvp>
171 <DaoNvp attr_name= "KF_FREIW_LSTG" attr_value_txt= "" attr_value_num= "0" >
172 </DaoNvp>
173 <DaoNvp attr_name= "DECKG_ESHD_CDCLS" attr_value_txt= "" attr_value_num= "1" >
174 </DaoNvp>
175 <DaoNvp attr_name= "OBJ_ID_HAFTG_ESHD" attr_value_txt= "UUID5e891b:eee984ee59:-7ab4" attr_value_num= "0" >
176 </DaoNvp>
177 <DaoNvp attr_name= "BVI_SC_EREIG" attr_value_txt= "" attr_value_num= "0" >
178 </DaoNvp>
179 <DaoNvp attr_name= "BVI_FZ_VN" attr_value_txt= "" attr_value_num= "8" >
180 </DaoNvp>
181 <DaoNvp attr_name= "VTRG_BR_CDU" attr_value_txt= "" attr_value_num= "99000" >
182 </DaoNvp>
183 <DaoNvp attr_name= "HAFTG_ESHD_CDCLS" attr_value_txt= "" attr_value_num= "1" >
184 </DaoNvp>
185 <DaoNvp attr_name= "BVI_DATENLAGE" attr_value_txt= "" attr_value_num= "0" >
186 </DaoNvp>
187 <DaoNvp attr_name= "OBJ_ID_REGR_ESHD" attr_value_txt= "UUID5e891b:eee984ee59:-7ab6" attr_value_num= "0" >
188 </DaoNvp>
189 <DaoNvp attr_name= "REGR_ESHD_CDCLS" attr_value_txt= "" attr_value_num= "2" >
190 </DaoNvp>
191 <DaoNvp attr_name= "KF_BVM_VDACHT_MANU" attr_value_txt= "" attr_value_num= "0" >
192 </DaoNvp>
193 <DaoNvp attr_name= "BVI_PERS_VN" attr_value_txt= "" attr_value_num= "7" >
194 </DaoNvp>
195 <DaoNvp attr_name= "BVI_PRUEFG" attr_value_txt= "" attr_value_num= "0" >
196 </DaoNvp>
197 <DaoNvp attr_name= "BVI_PERS_ANSPRSTR" attr_value_txt= "" attr_value_num= "5" >
198 </DaoNvp>
199 <DaoNvp attr_name= "OBJ_ID_MZ_MF_HAFT" attr_value_txt= "UUID5e891b:eee984ee59:-7acf" attr_value_num= "0" >
200 </DaoNvp>
201 <DaoNvp attr_name= "BVI_LENKR_ANSPRSTR" attr_value_txt= "" attr_value_num= "17" >
202 </DaoNvp>
203 <DaoNvp attr_name= "OBJ_ID_DECKG_ESHD" attr_value_txt= "UUID5e891b:eee984ee59:-7ab7" attr_value_num= "0" >
204 </DaoNvp>
205 <DaoNvp attr_name= "BVI_KOMP" attr_value_txt= "" attr_value_num= "0" >
206 </DaoNvp>
207 <DaoNvp attr_name= "V_BR_CDU_SC" attr_value_txt= "" attr_value_num= "99010" >
208 </DaoNvp>
209 <DaoNvp attr_name= "OBJ_ID_BVM_VDACHT" attr_value_txt= "UUID5e891b:eee984ee59:-7ab5" attr_value_num= "0" >
210 </DaoNvp>
211 <DaoNvp attr_name= "BVI_SC" attr_value_txt= "" attr_value_num= "0" >
212 </DaoNvp>
213 <DaoNvp attr_name= "BVI_VTRG_VN" attr_value_txt= "" attr_value_num= "0" >
214 </DaoNvp>
215 <DaoNvp attr_name= "OBJ_ID_BVM_RESULT" attr_value_txt= "UUID5e891b:eee984ee59:-7aac" attr_value_num= "0" >
216 </DaoNvp>
217 <DaoNvp attr_name= "BVI_LENKR_VN" attr_value_txt= "" attr_value_num= "1" >
218 </DaoNvp>
219 <DaoNvp attr_name= "BVI_FZ_ANSPRSTR" attr_value_txt= "" attr_value_num= "0" >
220 </DaoNvp>
221 <DaoNvp attr_name= "KZ_BETRUG_VDACHT" attr_value_txt= "" attr_value_num= "0" >
222 </DaoNvp>
223 </nvp_liste>
224 </DaoMldgZusMfh>
225 </mldg_zus_mfh_liste>
226 <mldg_zus_mfu_liste length= "0"></mldg_zus_mfu_liste>
227 <mldg_zus_hausrat_liste length= "0"></mldg_zus_hausrat_liste>
228 <mldg_zus_haph_liste length= "0"></mldg_zus_haph_liste>
229 <mldg_zus_allg_haft_liste length= "0"></mldg_zus_allg_haft_liste>
230 <mldg_zus_Ueb_Br_liste length= "0"></mldg_zus_Ueb_Br_liste>
231 <part_rol_glob_liste length= "6"><DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "0001-01-01" >
232 <nvp_liste length= "3"><DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID371566:eee983d86f:-5d88" attr_value_num= "0" >
233 </DaoNvp>
234 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "300" >
235 </DaoNvp>
236 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "27635" >
237 </DaoNvp>
238 </nvp_liste>
239 </DaoPartRolGlob>
240 <DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "0001-01-01" >
241 <nvp_liste length= "3"><DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID5e891b:eee984ee59:-7adf" attr_value_num= "0" >
242 </DaoNvp>
243 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "100" >
244 </DaoNvp>
245 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "2780" >
246 </DaoNvp>
247 </nvp_liste>
248 </DaoPartRolGlob>
249 <DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "0001-01-01" >
250 <nvp_liste length= "3"><DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID5e891b:eee984ee59:-7acd" attr_value_num= "0" >
251 </DaoNvp>
252 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "200" >
253 </DaoNvp>
254 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "27635" >
255 </DaoNvp>
256 </nvp_liste>
257 </DaoPartRolGlob>
258 <DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "0001-01-01" >
259 <nvp_liste length= "3"><DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID5e891b:eee984ee59:-7ad7" attr_value_num= "0" >
260 </DaoNvp>
261 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "200" >
262 </DaoNvp>
263 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "30584" >
264 </DaoNvp>
265 </nvp_liste>
266 </DaoPartRolGlob>
267 <DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "0001-01-01" >
268 <nvp_liste length= "4"><DaoNvp attr_name= "PERS_AWAHL_CDCLS" attr_value_txt= "" attr_value_num= "3" >
269 </DaoNvp>
270 <DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID5e891b:eee984ee59:-7ad5" attr_value_num= "0" >
271 </DaoNvp>
272 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "150" >
273 </DaoNvp>
274 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "2357" >
275 </DaoNvp>
276 </nvp_liste>
277 </DaoPartRolGlob>
278 <DaoPartRolGlob zus_beschr_fvr= "" vursg_bgruendg= "" austlg_dat_fueaw= "1980-01-01" >
279 <nvp_liste length= "10"><DaoNvp attr_name= "KF_LENKR_VOLLM" attr_value_txt= "" attr_value_num= "1" >
280 </DaoNvp>
281 <DaoNvp attr_name= "KF_VMIETG_GGBN" attr_value_txt= "" attr_value_num= "0" >
282 </DaoNvp>
283 <DaoNvp attr_name= "KF_LENKR_IDNST_VN" attr_value_txt= "" attr_value_num= "1" >
284 </DaoNvp>
285 <DaoNvp attr_name= "PERS_AWAHL_CDCLS" attr_value_txt= "" attr_value_num= "3" >
286 </DaoNvp>
287 <DaoNvp attr_name= "KF_VWANDT_MIT_VN" attr_value_txt= "" attr_value_num= "0" >
288 </DaoNvp>
289 <DaoNvp attr_name= "ADR_NR" attr_value_txt= "" attr_value_num= "2357" >
290 </DaoNvp>
291 <DaoNvp attr_name= "KF_LFUEAW_VORHD" attr_value_txt= "" attr_value_num= "0" >
292 </DaoNvp>
293 <DaoNvp attr_name= "OBJ_ID_PART_ROL" attr_value_txt= "UUID5e891b:eee984ee59:-7ad4" attr_value_num= "0" >
294 </DaoNvp>
295 <DaoNvp attr_name= "LAND_CDI_FUEAW" attr_value_txt= "TAD" attr_value_num= "0" >
296 </DaoNvp>
297 <DaoNvp attr_name= "PART_ROL_CDCLS" attr_value_txt= "" attr_value_num= "301" >
298 </DaoNvp>
299 </nvp_liste>
300 </DaoPartRolGlob>
301 </part_rol_glob_liste>
302 <sco_gbd_liste length= "0"></sco_gbd_liste>
303 <sco_pers_liste length= "0"></sco_pers_liste>
304 <sco_fz_liste length= "1"><DaoScoFz zus_beschr_fvr= "" bschaedg_ergzg= "" sc_btrg_schaetz= "0.0" exp_weitltg_dat= "0001-01-01" reptr_mldg_dat= "0001-01-01" bsichtg_dat= "0001-01-01" beg_dat_reptr= "0001-01-01" bsichtg_zeit= "00.00.00" >
305 <pvd_vmitlg_liste length= "0"></pvd_vmitlg_liste>
306 <part_rol_liste length= "1"><DaoPartRol part_rol_cdcls= "200" adr_nr= "27635" part_id= "-1" >
307 </DaoPartRol>
308 </part_rol_liste>
309 <sca_fz_liste length= "0"></sca_fz_liste>
310 <nvp_liste length= "24"><DaoNvp attr_name= "INVSE" attr_value_txt= "2001" attr_value_num= "0" >
311 </DaoNvp>
312 <DaoNvp attr_name= "ANZ_AIRBAG" attr_value_txt= "" attr_value_num= "0" >
313 </DaoNvp>
314 <DaoNvp attr_name= "KSCHILD_NR" attr_value_txt= "GE 516065" attr_value_num= "0" >
315 </DaoNvp>
316 <DaoNvp attr_name= "KZ_SCHEIBEN_GRAVUR" attr_value_txt= "" attr_value_num= "0" >
317 </DaoNvp>
318 <DaoNvp attr_name= "STAMM_NR" attr_value_txt= " 165160654" attr_value_num= "0" >
319 </DaoNvp>
320 <DaoNvp attr_name= "KMST" attr_value_txt= "" attr_value_num= "0" >
321 </DaoNvp>
322 <DaoNvp attr_name= "FZ_MARKE_TYP_CDTPR" attr_value_txt= "" attr_value_num= "1020624" >
323 </DaoNvp>
324 <DaoNvp attr_name= "OBJ_ID_SO_FZ" attr_value_txt= "UUID371566:eee983d86f:-592b" attr_value_num= "0" >
325 </DaoNvp>
326 <DaoNvp attr_name= "ANZ_SPLATZ" attr_value_txt= "" attr_value_num= "5" >
327 </DaoNvp>
328 <DaoNvp attr_name= "LEERGEWICHT" attr_value_txt= "" attr_value_num= "1570" >
329 </DaoNvp>
330 <DaoNvp attr_name= "WAEH_CDI_SCHAETZ" attr_value_txt= "CHF" attr_value_num= "0" >
331 </DaoNvp>
332 <DaoNvp attr_name= "KZ_ABS" attr_value_txt= "" attr_value_num= "1" >
333 </DaoNvp>
334 <DaoNvp attr_name= "KF_WV_VERS" attr_value_txt= "" attr_value_num= "1" >
335 </DaoNvp>
336 <DaoNvp attr_name= "HUBRAUM" attr_value_txt= "" attr_value_num= "2290" >
337 </DaoNvp>
338 <DaoNvp attr_name= "FZ_MARKE_TYP_BEZ" attr_value_txt= "Saab 9-5 2.3T Aero" attr_value_num= "0" >
339 </DaoNvp>
340 <DaoNvp attr_name= "KF_LEASING" attr_value_txt= "" attr_value_num= "0" >
341 </DaoNvp>
342 <DaoNvp attr_name= "KMST_AKTL" attr_value_txt= "" attr_value_num= "0" >
343 </DaoNvp>
344 <DaoNvp attr_name= "KZ_DIEBS_SICHG" attr_value_txt= "" attr_value_num= "1" >
345 </DaoNvp>
346 <DaoNvp attr_name= "FZ_ART_CDTPR" attr_value_txt= "" attr_value_num= "2" >
347 </DaoNvp>
348 <DaoNvp attr_name= "FZ_WERT" attr_value_txt= "" attr_value_num= "59900" >
349 </DaoNvp>
350 <DaoNvp attr_name= "OBJ_ID_BSCHAED_FZ" attr_value_txt= "UUID5e891b:eee984ee59:-7acc" attr_value_num= "0" >
351 </DaoNvp>
352 <DaoNvp attr_name= "FZ_ZBHR_WEIT" attr_value_txt= "" attr_value_num= "0" >
353 </DaoNvp>
354 <DaoNvp attr_name= "FZ_TYP_CDCLS" attr_value_txt= "" attr_value_num= "0" >
355 </DaoNvp>
356 <DaoNvp attr_name= "FZ_KATLG_PREIS" attr_value_txt= "" attr_value_num= "59900" >
357 </DaoNvp>
358 </nvp_liste>
359 </DaoScoFz>
360 </sco_fz_liste>
361 <sco_fh_liste length= "0"></sco_fh_liste>
362 <nvp_liste length= "40"><DaoNvp attr_name= "VSIGN_VN_CDCLS" attr_value_txt= "" attr_value_num= "1" >
363 </DaoNvp>
364 <DaoNvp attr_name= "LAND_CDI" attr_value_txt= "CH" attr_value_num= "0" >
365 </DaoNvp>
366 <DaoNvp attr_name= "KZ_SC_DAT_ZRAUM" attr_value_txt= "" attr_value_num= "0" >
367 </DaoNvp>
368 <DaoNvp attr_name= "STR" attr_value_txt= "Gossauerstrasse 111" attr_value_num= "0" >
369 </DaoNvp>
370 <DaoNvp attr_name= "OBJ_ID_MZ_VKEHR" attr_value_txt= "UUID5e891b:eee984ee59:-7abf" attr_value_num= "0" >
371 </DaoNvp>
372 <DaoNvp attr_name= "KZ_SC_ZEIT_ZRAUM" attr_value_txt= "" attr_value_num= "0" >
373 </DaoNvp>
374 <DaoNvp attr_name= "KF_SVERHT_DUNKEL" attr_value_txt= "" attr_value_num= "1" >
375 </DaoNvp>
376 <DaoNvp attr_name= "ORT" attr_value_txt= "St. Gallen-Winkeln" attr_value_num= "0" >
377 </DaoNvp>
378 <DaoNvp attr_name= "KF_PERS_VLTZG" attr_value_txt= "" attr_value_num= "0" >
379 </DaoNvp>
380 <DaoNvp attr_name= "KF_SVERHT_REGEN" attr_value_txt= "" attr_value_num= "1" >
381 </DaoNvp>
382 <DaoNvp attr_name= "KZ_STR_ART_HSTR" attr_value_txt= "" attr_value_num= "1" >
383 </DaoNvp>
384 <DaoNvp attr_name= "GSCHW_GP" attr_value_txt= "66" attr_value_num= "0" >
385 </DaoNvp>
386 <DaoNvp attr_name= "VLTZG_GRAD_CDCLS" attr_value_txt= "" attr_value_num= "0" >
387 </DaoNvp>
388 <DaoNvp attr_name= "TEL_POLIZ_POSTEN" attr_value_txt= "000111222" attr_value_num= "0" >
389 </DaoNvp>
390 <DaoNvp attr_name= "OBJ_ID_ERMD" attr_value_txt= "UUID5e891b:eee984ee59:-7ade" attr_value_num= "0" >
391 </DaoNvp>
392 <DaoNvp attr_name= "GSCHW_VN" attr_value_txt= "55" attr_value_num= "0" >
393 </DaoNvp>
394 <DaoNvp attr_name= "ERHG_TYP_CDCLS" attr_value_txt= "" attr_value_num= "1" >
395 </DaoNvp>
396 <DaoNvp attr_name= "KZ_STR_ART_WSTR" attr_value_txt= "" attr_value_num= "0" >
397 </DaoNvp>
398 <DaoNvp attr_name= "KF_UNF_PROT_VORHD" attr_value_txt= "" attr_value_num= "1" >
399 </DaoNvp>
400 <DaoNvp attr_name= "STR_VLAUF_GP_CDCLS" attr_value_txt= "" attr_value_num= "2" >
401 </DaoNvp>
402 <DaoNvp attr_name= "OBJ_ID_POLIZ_RAPP" attr_value_txt= "UUID5e891b:eee984ee59:-7abe" attr_value_num= "0" >
403 </DaoNvp>
404 <DaoNvp attr_name= "KZ_STR_ART_AUSORT" attr_value_txt= "" attr_value_num= "1" >
405 </DaoNvp>
406 <DaoNvp attr_name= "KZ_SC_DAT_UGN" attr_value_txt= "" attr_value_num= "0" >
407 </DaoNvp>
408 <DaoNvp attr_name= "KZ_STR_ART_AUTOB" attr_value_txt= "" attr_value_num= "0" >
409 </DaoNvp>
410 <DaoNvp attr_name= "KF_VURSR_UBKNT" attr_value_txt= "" attr_value_num= "0" >
411 </DaoNvp>
412 <DaoNvp attr_name= "KF_POLIZ_RAPP_VORH" attr_value_txt= "" attr_value_num= "1" >
413 </DaoNvp>
414 <DaoNvp attr_name= "KZ_SC_ZEIT_UGN" attr_value_txt= "" attr_value_num= "0" >
415 </DaoNvp>
416 <DaoNvp attr_name= "STR_VLAUF_VN_CDCLS" attr_value_txt= "" attr_value_num= "1" >
417 </DaoNvp>
418 <DaoNvp attr_name= "KZ_STR_ART_NSTR" attr_value_txt= "" attr_value_num= "0" >
419 </DaoNvp>
420 <DaoNvp attr_name= "NAME_POLIZ_BEAMT" attr_value_txt= "P. Schmierler" attr_value_num= "0" >
421 </DaoNvp>
422 <DaoNvp attr_name= "ERHG_KBESCHR_CDCLS" attr_value_txt= "" attr_value_num= "5" >
423 </DaoNvp>
424 <DaoNvp attr_name= "ERMD_TYP_CDCLS" attr_value_txt= "" attr_value_num= "1" >
425 </DaoNvp>
426 <DaoNvp attr_name= "VSIGN_GP_CDCLS" attr_value_txt= "" attr_value_num= "2" >
427 </DaoNvp>
428 <DaoNvp attr_name= "STR_ZUST_CDCLS" attr_value_txt= "" attr_value_num= "1" >
429 </DaoNvp>
430 <DaoNvp attr_name= "POLIZ_POSTEN_BEZ" attr_value_txt= "Kapo Autobahn" attr_value_num= "0" >
431 </DaoNvp>
432 <DaoNvp attr_name= "KF_H3_ANSPR_GGBN" attr_value_txt= "" attr_value_num= "1" >
433 </DaoNvp>
434 <DaoNvp attr_name= "SCHUFRA_CDCLS" attr_value_txt= "" attr_value_num= "1" >
435 </DaoNvp>
436 <DaoNvp attr_name= "KF_SVERHT_NEBEL" attr_value_txt= "" attr_value_num= "1" >
437 </DaoNvp>
438 <DaoNvp attr_name= "PLZ" attr_value_txt= "9000" attr_value_num= "0" >
439 </DaoNvp>
440 <DaoNvp attr_name= "KZ_STR_ART_INORT" attr_value_txt= "" attr_value_num= "1" >
441 </DaoNvp>
442 </nvp_liste>
443 </DaoEreigMldg>
444 </ereig_mldg_liste>
445 <kntkt_liste length= "0"></kntkt_liste>
446 <nvp_liste length= "5"><DaoNvp attr_name= "KF_TC_FALL" attr_value_txt= "" attr_value_num= "1" >
447 </DaoNvp>
448 <DaoNvp attr_name= "ERDO_STAT_CDCLS" attr_value_txt= "" attr_value_num= "1" >
449 </DaoNvp>
450 <DaoNvp attr_name= "DIR_ZTLG_CDCLS" attr_value_txt= "" attr_value_num= "100" >
451 </DaoNvp>
452 <DaoNvp attr_name= "OBJ_ID_ERDO" attr_value_txt= "UUID5e891b:eee984ee59:-7ad1" attr_value_num= "0" >
453 </DaoNvp>
454 <DaoNvp attr_name= "OBJ_ID_FALL_ZTLG" attr_value_txt= "UUID5e891b:eee984ee59:-7aab" attr_value_num= "0" >
455 </DaoNvp>
456 </nvp_liste>
457 </DaoEreigDossier>
0 <?xml version="1.0"?>
1 <openSource xmlns="http://xmlunit.sourceforge.net/tests"
2 xmlns:junit="http://www.junit.org"
3 xmlns:eclipse="http://www.eclipse.org"
4 xmlns:jakarta="http://jakarta.apache.org">
5 <tool junit:version="3.8.1">jUnit</tool>
6 <tool eclipse:version="2.1">eclipse</tool>
7 <tool jakarta:version="1.5.1">ant</tool>
8 <tool jakarta:version="2.4">xalan</tool>
9 <tool jakarta:version="2.0.1">xerces</tool>
10 </openSource>
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39
40 import junit.framework.TestCase;
41
42 /**
43 * JUnit test for DoctypeReader and DoctypeInputStream
44 */
45 public abstract class AbstractDoctypeTests extends TestCase {
46
47 private static final String COMMENT = "<!-- comment -->";
48 protected static final String NO_DTD =
49 "<document><element>one</element></document>";
50
51 public abstract void testGetContent() throws IOException;
52
53 protected abstract void assertEquals(String expected, String input,
54 String docType, String systemId)
55 throws IOException;
56
57 public void testRead() throws IOException {
58 String oz = "Chirurgische Verbesserungen sind g\u00fcnstig";
59 assertEquals("<!DOCTYPE Kylie SYSTEM \"bumJob\">" + oz,
60 oz, "Kylie", "bumJob");
61 }
62
63 public void testInternalDTD() throws IOException {
64 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">",
65 test_Constants.CHUCK_JONES_RIP_DTD_DECL, "ni",
66 "shrubbery");
67 }
68
69 public void testExternalDTD() throws IOException {
70 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">",
71 "<! DOCTYPE PUBLIC \"yak\" SYSTEM \"llama\">", "ni",
72 "shrubbery");
73 }
74
75 public void testNoDTD() throws IOException {
76 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD,
77 NO_DTD, "ni", "shrubbery");
78 }
79
80 public void testNoDTDButXMLDecl() throws IOException {
81 assertEquals(test_Constants.XML_DECLARATION
82 + "<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD,
83 test_Constants.XML_DECLARATION + NO_DTD,
84 "ni", "shrubbery");
85 }
86
87 public void testInternalDTDWithComment() throws IOException {
88 assertEquals(test_Constants.XML_DECLARATION
89 + "<!DOCTYPE ni SYSTEM \"shrubbery\">"
90 + COMMENT,
91 test_Constants.XML_DECLARATION
92 + COMMENT
93 + test_Constants.CHUCK_JONES_RIP_DTD_DECL,
94 "ni", "shrubbery");
95 }
96
97 public void testExternalDTDWithComment() throws IOException {
98 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">"
99 + COMMENT,
100 COMMENT + "<! DOCTYPE PUBLIC \"yak\" SYSTEM \"llama\">",
101 "ni", "shrubbery");
102 }
103
104 public void testNoDTDWithComment() throws IOException {
105 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">" + COMMENT + NO_DTD,
106 COMMENT + NO_DTD, "ni", "shrubbery");
107 }
108
109 public void testNoDTDButXMLDeclWithComment() throws IOException {
110 assertEquals(test_Constants.XML_DECLARATION
111 + "<!DOCTYPE ni SYSTEM \"shrubbery\">" + COMMENT + NO_DTD,
112 test_Constants.XML_DECLARATION + COMMENT + NO_DTD,
113 "ni", "shrubbery");
114 }
115
116 public AbstractDoctypeTests(String name) {
117 super(name);
118 }
119 }
120
0 /*
1 ******************************************************************
2 Copyright (c) 2007-2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.HashMap;
39 import junit.framework.TestCase;
40 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
41 import org.custommonkey.xmlunit.exceptions.XpathException;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.NamedNodeMap;
44 import org.w3c.dom.Node;
45 import org.w3c.dom.NodeList;
46
47 public abstract class AbstractXpathEngineTests extends TestCase {
48
49 protected static final String[] testAttrNames = {"attrOne", "attrTwo"};
50
51 protected static final String testString =
52 "<test><nodeWithoutAttributes>intellectual property rights"
53 + " </nodeWithoutAttributes>"
54 + "<nodeWithoutAttributes>make us all poorer </nodeWithoutAttributes>"
55 + "<nodeWithAttributes " + testAttrNames[0] + "=\"open source \" "
56 + testAttrNames[1]
57 + "=\"is the answer \">free your code from its chains"
58 + "</nodeWithAttributes></test>";
59 protected Document testDocument;
60
61 protected abstract XpathEngine newXpathEngine();
62
63 public void testGetMatchingNodesNoMatches() throws Exception {
64 NodeList nodeList = newXpathEngine().getMatchingNodes("toast",
65 testDocument);
66 assertEquals(0, nodeList.getLength());
67 }
68
69 public void testGetMatchingNodesMatchRootElement() throws Exception {
70 NodeList nodeList = newXpathEngine().getMatchingNodes("test",
71 testDocument);
72 assertEquals(1, nodeList.getLength());
73 assertEquals(Node.ELEMENT_NODE, nodeList.item(0).getNodeType());
74 }
75
76 public void testGetMatchingNodesMatchElement() throws Exception {
77 NodeList nodeList = newXpathEngine()
78 .getMatchingNodes("test/nodeWithoutAttributes", testDocument);
79 assertEquals(2, nodeList.getLength());
80 assertEquals(Node.ELEMENT_NODE, nodeList.item(0).getNodeType());
81 }
82
83 public void testGetMatchingNodesMatchText() throws Exception {
84 NodeList nodeList = newXpathEngine().getMatchingNodes("test//text()",
85 testDocument);
86 assertEquals(3, nodeList.getLength());
87 assertEquals(Node.TEXT_NODE, nodeList.item(0).getNodeType());
88 }
89
90 public void testGetMatchingNodesCheckSubNodes() throws Exception {
91 NodeList nodeList = newXpathEngine()
92 .getMatchingNodes("test/nodeWithAttributes", testDocument);
93 assertEquals(1, nodeList.getLength());
94 Node aNode;
95
96 aNode = nodeList.item(0);
97 assertEquals(Node.ELEMENT_NODE, aNode.getNodeType());
98 assertEquals(true, aNode.hasAttributes());
99 assertEquals(true, aNode.hasChildNodes());
100
101 NodeList children = aNode.getChildNodes();
102 int length = children.getLength();
103 assertEquals(1, length);
104 for (int i=0; i < length; ++i) {
105 assertEquals(Node.TEXT_NODE, children.item(i).getNodeType());
106 }
107
108 NamedNodeMap attributes = aNode.getAttributes();
109 int numAttrs = attributes.getLength();
110 assertEquals(testAttrNames.length, numAttrs);
111 for (int i=0; i < testAttrNames.length; ++i) {
112 Node attrNode = attributes.getNamedItem(testAttrNames[i]);
113 assertNotNull(attrNode);
114 assertEquals(Node.ATTRIBUTE_NODE, attrNode.getNodeType());
115 }
116 }
117
118 public void testEvaluate() throws Exception {
119 String result = newXpathEngine().evaluate("count(test//node())",
120 testDocument);
121 assertEquals("3 elements and 3 text nodes", "6", result);
122 }
123
124 public void testXpathPrefixChange() throws Exception {
125 String testDoc = "<t:test xmlns:t=\"urn:foo\"><t:bar/></t:test>";
126 Document d = XMLUnit.buildControlDocument(testDoc);
127 HashMap m = new HashMap();
128 m.put("foo", "urn:foo");
129 NamespaceContext ctx = new SimpleNamespaceContext(m);
130 XpathEngine engine = newXpathEngine();
131 engine.setNamespaceContext(ctx);
132
133 NodeList l = engine.getMatchingNodes("//foo:bar", d);
134 assertEquals(1, l.getLength());
135 assertEquals(Node.ELEMENT_NODE, l.item(0).getNodeType());
136
137 String s = engine.evaluate("count(foo:test//node())", d);
138 assertEquals("1", s);
139 }
140
141 // http://sourceforge.net/forum/forum.php?thread_id=1832061&forum_id=73274
142 public void testXpathExistsWithNsAndLocalNameSelector() throws Exception {
143 String testDoc =
144 "<MtcEnv Version=\"1.0\" xmlns=\"http://www.Mtc.com/schemas\" xmlns:bms=\"http://www.cieca.com/BMS\"> "
145 + "<EnvContext> "
146 + "<NameValuePair> "
147 + "<Name>Timestamp</Name> "
148 + "<Value>2007-07-26T11:59:00</Value> "
149 + "</NameValuePair> "
150 + "</EnvContext> "
151 + "<EnvBodyList> "
152 + "<EnvBody> "
153 + "<Metadata> "
154 + "<Identifier>CIECABMSAssignmentAddRq</Identifier> "
155 + "</Metadata> "
156 + "<Content> "
157 + "<bms:CIECA> "
158 + "<bms:AssignmentAddRq> "
159 + "<bms:RqUID>3744f84b-ac18-5303-0082-764bdeb20df9</bms:RqUID> "
160 + "</bms:AssignmentAddRq> "
161 + "</bms:CIECA> "
162 + "</Content> "
163 + "</EnvBody> "
164 + "</EnvBodyList> "
165 + "</MtcEnv>";
166 Document d = XMLUnit.buildControlDocument(testDoc);
167
168 XpathEngine engine = newXpathEngine();
169 NodeList l =
170 engine.getMatchingNodes("//*[local-name()='RqUID'][namespace-uri()='http://www.cieca.com/BMS']", d);
171 assertEquals(1, l.getLength());
172 }
173
174 public void setUp() throws Exception {
175 testDocument = XMLUnit.buildControlDocument(testString);
176 }
177
178 public AbstractXpathEngineTests(String name) {
179 super(name);
180 }
181
182
183 public void testEvaluateInvalidXPath() throws Exception {
184 String xpath = "count(test//*[@attrOne='open source])";
185 try {
186 String result = newXpathEngine().evaluate(xpath, testDocument);
187 fail("expected Exception to be thrown but wasn't");
188 } catch (XpathException ex) {
189 // expected
190 } catch (ConfigurationException ex) {
191 // acceptable in the JAXP 1.2 case
192 }
193 }
194
195 // https://sourceforge.net/forum/forum.php?thread_id=3292605&forum_id=73274
196 public void testDefaultNamespace() throws Exception {
197 String t = "<a xmlns=\"http://www.acme.com\"><b c='cv'>bv</b></a>";
198
199 Document d = XMLUnit.buildControlDocument(t);
200 HashMap m = new HashMap();
201 m.put("", "http://www.acme.com");
202 m.put("q", "http://www.acme.com");
203
204 NamespaceContext ctx = new SimpleNamespaceContext(m);
205 XpathEngine engine = newXpathEngine();
206 engine.setNamespaceContext(ctx);
207 // fails assertEquals("bv", engine.evaluate("//b", d));
208 assertEquals("bv", engine.evaluate("//q:b", d));
209 }
210 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 /**
39 * Performs replacement of one String by another String
40 * within one or more Strings.
41 * This was once required but a code refactoring made it redundant and I don't have
42 * the heart to kill it off...!
43 */
44 public class Replacement {
45 private final char[] ofChars;
46 private final char[] byChars;
47
48 public Replacement(String ofString, String byString) {
49 this(ofString.toCharArray(),
50 byString == null ? null : byString.toCharArray());
51 }
52
53 public Replacement(char[] ofChars, char[] byChars) {
54 this.ofChars = ofChars;
55 this.byChars = byChars;
56 }
57
58 public final String replace(String inString) {
59 StringBuffer buf = replaceAndAppend(inString.toCharArray(),
60 new StringBuffer(inString.length()));
61
62 return buf.toString();
63 }
64
65 public final char[] replace(char[] inChars) {
66 StringBuffer buf = replaceAndAppend(inChars,
67 new StringBuffer(inChars.length));
68
69 char[] replacement = new char[buf.length()];
70 buf.getChars(0, buf.length(), replacement, 0);
71
72 return replacement;
73 }
74
75 public final StringBuffer replaceAndAppend(char[] inChars,
76 StringBuffer toBuffer) {
77 int ofPos = 0;
78 int falseStartPos = -1;
79 for (int i=0; i < inChars.length; ++i) {
80 if (inChars[i] == ofChars[ofPos]) {
81 if (falseStartPos == -1) {
82 falseStartPos = i;
83 }
84 ++ofPos;
85 } else {
86 ofPos = 0;
87 if (falseStartPos != -1) {
88 for (; falseStartPos < i; ++falseStartPos) {
89 toBuffer.append(inChars[falseStartPos]);
90 }
91 falseStartPos = -1;
92 }
93 toBuffer.append(inChars[i]);
94 }
95
96 if (ofPos == ofChars.length) {
97 if (hasReplaceBy()) {
98 toBuffer.append(byChars);
99 }
100 ofPos = 0;
101 falseStartPos = -1;
102 }
103 }
104
105 return toBuffer;
106 }
107
108 public boolean hasReplaceBy() {
109 return byChars != null && byChars.length > 0;
110 }
111 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39 import java.io.InputStreamReader;
40 import java.io.UnsupportedEncodingException;
41 import java.util.Properties;
42
43 import org.w3c.dom.Node;
44
45 /**
46 * Simple serialization class that uses a NodeInputStream (and hence
47 * a DOM-to-Stream identity transformation) to perform the work.
48 * This is not an efficient process for serialization, but it is portable
49 * across underlying transform implementations which always comes in handy...
50 * Only used so far for testing hence it's position in the test side of the
51 * source tree.
52 */
53 public class SimpleSerializer {
54 private final int bufferSize;
55 private final Properties outputProperties;
56
57 /**
58 * Construct a new instance with default buffer size
59 */
60 public SimpleSerializer() {
61 this(1024);
62 }
63
64 /**
65 * Construct a new instance with specific buffer size (handy for large
66 * documents)
67 */
68 public SimpleSerializer(int bufferSize) {
69 this.bufferSize = bufferSize;
70 outputProperties = new Properties();
71 }
72
73 /**
74 * Set an output property for the serialied form
75 * @param name
76 * @param value
77 * @see javax.xml.transform.OutputKeys
78 */
79 public void setOutputProperty(String name, String value) {
80 outputProperties.setProperty(name, value);
81 }
82
83 /**
84 * Serialize a Node to a String with default String encoding
85 * @param domNode
86 * @return full String representation of Node
87 * @throws IOException
88 * @throws UnsupportedEncodingException
89 */
90 public String serialize(Node domNode)
91 throws IOException, UnsupportedEncodingException {
92 return serialize(domNode, null);
93 }
94
95 /**
96 * Serialize a Node to a String with specific String encoding
97 * @param domNode
98 * @return full String representation of Node
99 * @throws IOException
100 * @throws UnsupportedEncodingException
101 */
102 public String serialize(Node domNode, String encoding)
103 throws IOException, UnsupportedEncodingException {
104 NodeInputStream nodeStream = new NodeInputStream(domNode,
105 outputProperties);
106
107 InputStreamReader reader;
108 if (encoding == null) {
109 // use default encoding
110 reader = new InputStreamReader(nodeStream);
111 } else {
112 reader = new InputStreamReader(nodeStream, encoding);
113 }
114
115 StringBuffer buf = new StringBuffer();
116 char[] chars = new char[bufferSize];
117 int len;
118 while ((len = reader.read(chars))!=-1) {
119 buf.append(chars, 0, len);
120 }
121 reader.close();
122
123 return buf.toString();
124 }
125 }
126
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import java.util.Locale;
38 import junit.framework.TestCase;
39
40 import org.custommonkey.xmlunit.Diff;
41 import org.custommonkey.xmlunit.Difference;
42 import org.custommonkey.xmlunit.DifferenceListener;
43 import org.w3c.dom.Node;
44
45 public class test_CaseInsensitiveDifferenceListener extends TestCase {
46
47 private static final String ATTR = "aTtr";
48 private static final String CDATA = "C Data";
49 private static final String CMMT = "a Comment";
50 private static final String TEXT = "some Text";
51
52 public void testCaseInsensitive() throws Exception {
53 String control = getDoc(ATTR, CDATA, CMMT, TEXT);
54 String test = getDoc(ATTR.toUpperCase(Locale.US),
55 CDATA.toUpperCase(Locale.US),
56 CMMT.toUpperCase(Locale.US),
57 TEXT.toUpperCase(Locale.US));
58 Diff d = new Diff(control, test);
59
60 CaseInsensitiveDifferenceListener c =
61 new CaseInsensitiveDifferenceListener(new DifferenceListener() {
62 public int differenceFound(Difference d) {
63 fail("differenceFound shouldn't get invoked, but"
64 + " was with type " + d.getId());
65 return -42;
66 }
67 public void skippedComparison(Node c, Node t) {
68 fail("skippedComparison shouldn't get invoked");
69 }
70 });
71
72 d.overrideDifferenceListener(c);
73 assertTrue(d.identical());
74 }
75
76 private static String getDoc(String attr, String cdata, String comment,
77 String text) {
78 return "<root><first attr=\"" + attr + "\"/><!--" + comment + "-->"
79 + "<second><![CDATA[" + cdata + "]]></second><third>" + text
80 + "</third></root>";
81 }
82 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import java.io.StringReader;
39
40 import junit.framework.TestCase;
41
42 import org.custommonkey.xmlunit.NodeTest;
43 import org.custommonkey.xmlunit.NodeTestException;
44 import org.w3c.dom.Node;
45
46 /**
47 * JUnit test for CountingNodeTester
48 */
49 public class test_CountingNodeTester extends TestCase {
50 private NodeTest test;
51 private CountingNodeTester tester;
52
53 public void testPositivePath() throws Exception {
54 test = new NodeTest(new StringReader("<a><b>c</b></a>"));
55 tester = new CountingNodeTester(2);
56 test.performTest(tester, Node.ELEMENT_NODE);
57
58 tester = new CountingNodeTester(1);
59 test.performTest(tester, Node.TEXT_NODE);
60
61 tester = new CountingNodeTester(3);
62 test.performTest(tester,
63 new short[] {Node.TEXT_NODE, Node.ELEMENT_NODE});
64
65 tester = new CountingNodeTester(0);
66 test.performTest(tester, Node.COMMENT_NODE);
67 }
68
69 public void testNegativePath() throws Exception {
70 test = new NodeTest(new StringReader("<a><b>c</b></a>"));
71 try {
72 tester = new CountingNodeTester(2);
73 test.performTest(tester, Node.TEXT_NODE);
74 fail("Expected NodeTestException");
75 } catch (NodeTestException e) {
76 // failure, as expected
77 }
78
79 try {
80 tester = new CountingNodeTester(1);
81 test.performTest(tester, Node.ELEMENT_NODE);
82 fail("Expected NodeTestException");
83 } catch (NodeTestException e) {
84 // failure, as expected
85 }
86
87 try {
88 tester = new CountingNodeTester(2);
89 test.performTest(tester,
90 new short[] {Node.TEXT_NODE, Node.ELEMENT_NODE});
91 fail("Expected NodeTestException");
92 } catch (NodeTestException e) {
93 // failure, as expected
94 }
95
96 try {
97 tester = new CountingNodeTester(1);
98 test.performTest(tester, Node.COMMENT_NODE);
99 fail("Expected NodeTestException");
100 } catch (NodeTestException e) {
101 // failure, as expected
102 }
103
104 try {
105 tester = new CountingNodeTester(0);
106 test.performTest(tester, Node.TEXT_NODE);
107 fail("Expected NodeTestException");
108 } catch (NodeTestException e) {
109 // failure, as expected
110 }
111 }
112
113 public test_CountingNodeTester(String name) {
114 super(name);
115 }
116
117 }
118
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import java.util.Locale;
38 import junit.framework.TestCase;
39
40 import org.custommonkey.xmlunit.Diff;
41 import org.custommonkey.xmlunit.Difference;
42 import org.custommonkey.xmlunit.DifferenceListener;
43 import org.w3c.dom.Node;
44
45 public class test_FloatingPointTolerantDifferenceListener extends TestCase {
46
47 public void testFloatingPointTolerance() throws Exception {
48 String control = "<foo value=\"2.718281828\"/>";
49 String test = "<foo value=\"2.71\"/>";
50 Diff d = new Diff(control, test);
51
52 FloatingPointTolerantDifferenceListener c =
53 new FloatingPointTolerantDifferenceListener(new DifferenceListener() {
54 public int differenceFound(Difference d) {
55 fail("differenceFound shouldn't get invoked, but"
56 + " was with type " + d.getId());
57 return -42;
58 }
59 public void skippedComparison(Node c, Node t) {
60 fail("skippedComparison shouldn't get invoked");
61 }
62 }, 1e-2);
63
64 d.overrideDifferenceListener(c);
65 assertTrue(d.identical());
66
67 c = new FloatingPointTolerantDifferenceListener(new DifferenceListener() {
68 public int differenceFound(Difference d) {
69 fail("differenceFound shouldn't get invoked, but"
70 + " was with type " + d.getId());
71 return -42;
72 }
73 public void skippedComparison(Node c, Node t) {
74 fail("skippedComparison shouldn't get invoked");
75 }
76 }, 1e-3);
77
78 d = new Diff(control, test);
79 d.overrideDifferenceListener(c);
80 assertFalse(d.identical());
81 }
82
83 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 import org.custommonkey.xmlunit.Diff;
45 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
46 import org.custommonkey.xmlunit.ElementQualifier;
47 import org.custommonkey.xmlunit.XMLUnit;
48
49 /**
50 * JUnit testcase for MultiLevelElementNameAndTextQualifier
51 * @see test_Diff#testRepeatedElementNamesWithTextQualification()
52 */
53 public class test_MultiLevelElementNameAndTextQualifier extends TestCase {
54 private static final String TAG_NAME = "tagYoureIt";
55 private static final String TAG_NAME2 = "tagYoureIt2";
56 private static final String TEXT_A = "textA";
57 private static final String TEXT_B = "textB";
58 private Document document;
59
60 // copy of ElementNameAndTextQualifier test
61 public void testSingleTextValue() throws Exception {
62 ElementQualifier qualifier =
63 new MultiLevelElementNameAndTextQualifier(1);
64
65 Element control = document.createElement(TAG_NAME);
66 control.appendChild(document.createTextNode(TEXT_A));
67
68 Element test = document.createElement(TAG_NAME);
69
70 assertFalse("control text not comparable to empty text",
71 qualifier.qualifyForComparison(control, test));
72
73 test.appendChild(document.createTextNode(TEXT_A));
74 assertTrue("control textA comparable to test textA",
75 qualifier.qualifyForComparison(control, test));
76
77 test = document.createElement(TAG_NAME);
78
79 test.appendChild(document.createTextNode(TEXT_B));
80 assertFalse("control textA not comparable to test textB",
81 qualifier.qualifyForComparison(control, test));
82 }
83
84 // copy of ElementNameAndTextQualifier test
85 public void testMultipleTextValues() throws Exception {
86 ElementQualifier qualifier =
87 new MultiLevelElementNameAndTextQualifier(1);
88
89 Element control = document.createElement(TAG_NAME);
90 control.appendChild(document.createTextNode(TEXT_A));
91 control.appendChild(document.createTextNode(TEXT_B));
92
93 Element test = document.createElement(TAG_NAME);
94 test.appendChild(document.createTextNode(TEXT_A + TEXT_B));
95 assertTrue("denormalised control text comparable to normalised test text",
96 qualifier.qualifyForComparison(control, test));
97 }
98
99 // three levels
100 public void testThreeLevels() throws Exception {
101 ElementQualifier qualifier =
102 new MultiLevelElementNameAndTextQualifier(3);
103
104 Element control = document.createElement(TAG_NAME);
105 Element child = document.createElement(TAG_NAME2);
106 control.appendChild(child);
107 Element child2 = document.createElement(TAG_NAME);
108 child.appendChild(child2);
109 child2.appendChild(document.createTextNode(TEXT_B));
110
111 Element test = document.createElement(TAG_NAME);
112 child = document.createElement(TAG_NAME2);
113 test.appendChild(child);
114 child2 = document.createElement(TAG_NAME);
115 child.appendChild(child2);
116 child2.appendChild(document.createTextNode(TEXT_B));
117
118 assertTrue(qualifier.qualifyForComparison(control, test));
119 }
120
121 /**
122 * @see https://sourceforge.net/forum/forum.php?thread_id=1440169&forum_id=73274
123 */
124 public void testThread1440169() throws Exception {
125 String s1 = "<a><b><c>foo</c></b><b><c>bar</c></b></a>";
126 String s2 = "<a><b><c>bar</c></b><b><c>foo</c></b></a>";
127 Diff d = new Diff(s1, s2);
128 assertFalse(d.similar());
129
130 // reset
131 d = new Diff(s1, s2);
132 d.overrideElementQualifier(new ElementNameAndTextQualifier());
133 assertFalse(d.similar());
134
135 // reset once again
136 d = new Diff(s1, s2);
137 d.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2));
138 assertTrue(d.similar());
139
140 }
141
142 public void testUserGuideExample() throws Exception {
143 String control =
144 "<table>\n"
145 + " <tr>\n"
146 + " <td>foo</td>\n"
147 + " </tr>\n"
148 + " <tr>\n"
149 + " <td>bar</td>\n"
150 + " </tr>\n"
151 + "</table>\n";
152 String test =
153 "<table>\n"
154 + " <tr>\n"
155 + " <td>bar</td>\n"
156 + " </tr>\n"
157 + " <tr>\n"
158 + " <td>foo</td>\n"
159 + " </tr>\n"
160 + "</table>\n";
161
162 Diff d = new Diff(control, test);
163 d.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2));
164 assertFalse(d.toString(), d.similar());
165
166 try {
167 XMLUnit.setIgnoreWhitespace(true);
168 d = new Diff(control, test);
169 d.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2));
170 assertTrue(d.toString(), d.similar());
171 } finally {
172 XMLUnit.setIgnoreWhitespace(false);
173 }
174
175 d = new Diff(control, test);
176 d.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2,
177 true));
178 assertTrue(d.toString(), d.similar());
179 }
180
181 public void setUp() throws Exception {
182 document = XMLUnit.newControlParser().newDocument();
183 }
184
185 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008-2009,2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.examples;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 import org.custommonkey.xmlunit.Diff;
45 import org.custommonkey.xmlunit.XMLAssert;
46 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
47 import org.custommonkey.xmlunit.ElementQualifier;
48 import org.custommonkey.xmlunit.XMLUnit;
49
50 /**
51 * JUnit testcase for RecursiveElementNameAndTextQualifier with most
52 * tests copied from MultiLevelElementNameAndTextQualifier' test.
53 * @see test_Diff#testRepeatedElementNamesWithTextQualification()
54 */
55 public class test_RecursiveElementNameAndTextQualifier extends TestCase {
56 private static final String TAG_NAME = "tagYoureIt";
57 private static final String TAG_NAME2 = "tagYoureIt2";
58 private static final String TEXT_A = "textA";
59 private static final String TEXT_B = "textB";
60 private Document document;
61
62 // copy of ElementNameAndTextQualifier test
63 public void testSingleTextValue() throws Exception {
64 ElementQualifier qualifier =
65 new RecursiveElementNameAndTextQualifier();
66
67 Element control = document.createElement(TAG_NAME);
68 control.appendChild(document.createTextNode(TEXT_A));
69
70 Element test = document.createElement(TAG_NAME);
71
72 assertFalse("control text not comparable to empty text",
73 qualifier.qualifyForComparison(control, test));
74
75 test.appendChild(document.createTextNode(TEXT_A));
76 assertTrue("control textA comparable to test textA",
77 qualifier.qualifyForComparison(control, test));
78
79 test = document.createElement(TAG_NAME);
80
81 test.appendChild(document.createTextNode(TEXT_B));
82 assertFalse("control textA not comparable to test textB",
83 qualifier.qualifyForComparison(control, test));
84 }
85
86 // copy of ElementNameAndTextQualifier test
87 public void testMultipleTextValues() throws Exception {
88 ElementQualifier qualifier =
89 new RecursiveElementNameAndTextQualifier();
90
91 Element control = document.createElement(TAG_NAME);
92 control.appendChild(document.createTextNode(TEXT_A));
93 control.appendChild(document.createTextNode(TEXT_B));
94
95 Element test = document.createElement(TAG_NAME);
96 test.appendChild(document.createTextNode(TEXT_A + TEXT_B));
97 assertTrue("denormalised control text comparable to normalised test text",
98 qualifier.qualifyForComparison(control, test));
99 }
100
101 // three levels
102 public void testThreeLevels() throws Exception {
103 ElementQualifier qualifier =
104 new RecursiveElementNameAndTextQualifier();
105
106 Element control = document.createElement(TAG_NAME);
107 Element child = document.createElement(TAG_NAME2);
108 control.appendChild(child);
109 Element child2 = document.createElement(TAG_NAME);
110 child.appendChild(child2);
111 child2.appendChild(document.createTextNode(TEXT_B));
112
113 Element test = document.createElement(TAG_NAME);
114 child = document.createElement(TAG_NAME2);
115 test.appendChild(child);
116 child2 = document.createElement(TAG_NAME);
117 child.appendChild(child2);
118 child2.appendChild(document.createTextNode(TEXT_B));
119
120 assertTrue(qualifier.qualifyForComparison(control, test));
121 }
122
123 /**
124 * @see https://sourceforge.net/forum/forum.php?thread_id=1440169&forum_id=73274
125 */
126 public void testThread1440169() throws Exception {
127 String s1 = "<a><b><c>foo</c></b><b><c>bar</c></b></a>";
128 String s2 = "<a><b><c>bar</c></b><b><c>foo</c></b></a>";
129 Diff d = new Diff(s1, s2);
130 assertFalse(d.similar());
131
132 // reset
133 d = new Diff(s1, s2);
134 d.overrideElementQualifier(new ElementNameAndTextQualifier());
135 assertFalse(d.similar());
136
137 // reset once again
138 d = new Diff(s1, s2);
139 d.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
140 assertTrue(d.similar());
141
142 }
143
144 public void testUserGuideExample() throws Exception {
145 String control =
146 "<table>\n"
147 + " <tr>\n"
148 + " <td>foo</td>\n"
149 + " </tr>\n"
150 + " <tr>\n"
151 + " <td>bar</td>\n"
152 + " </tr>\n"
153 + "</table>\n";
154 String test =
155 "<table>\n"
156 + " <tr>\n"
157 + " <td>bar</td>\n"
158 + " </tr>\n"
159 + " <tr>\n"
160 + " <td>foo</td>\n"
161 + " </tr>\n"
162 + "</table>\n";
163
164 Diff d = new Diff(control, test);
165 d.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
166 assertTrue(d.toString(), d.similar());
167 }
168
169 /**
170 * @see "http://sourceforge.net/p/xmlunit/bugs/62/"
171 */
172 public void testMultipleTextValuesWithAdditionalElement() throws Exception {
173 ElementQualifier qualifier =
174 new RecursiveElementNameAndTextQualifier();
175
176 Element control = document.createElement(TAG_NAME);
177 control.appendChild(document.createTextNode(TEXT_A));
178 control.appendChild(document.createTextNode(TEXT_B));
179 control.appendChild(document.createElement(TAG_NAME));
180
181 Element test = document.createElement(TAG_NAME);
182 test.appendChild(document.createTextNode(TEXT_A + TEXT_B));
183 test.appendChild(document.createElement(TAG_NAME));
184 assertTrue("denormalised control text comparable to normalised test text",
185 qualifier.qualifyForComparison(control, test));
186 }
187
188 public void setUp() throws Exception {
189 document = XMLUnit.newControlParser().newDocument();
190 }
191
192 /**
193 * @see https://sourceforge.net/forum/forum.php?thread_id=2948005&amp;forum_id=73273
194 */
195 public void testOpenDiscussionThread2948995_1() throws Exception {
196 Diff myDiff = new Diff("<root>"
197 + " <ent>"
198 + " <value>"
199 + " <int>1</int>"
200 + " </value>"
201 + " <value>"
202 + " <int>2</int>"
203 + " </value>"
204 + " </ent>"
205 + " <ent>"
206 + " <value>"
207 + " <int>3</int>"
208 + " </value>"
209 + " <value>"
210 + " <int>4</int>"
211 + " </value>"
212 + " </ent>"
213 + "</root>",
214 "<root>"
215 + " <ent>"
216 + " <value>"
217 + " <int>2</int>"
218 + " </value>"
219 + " <value>"
220 + " <int>1</int>"
221 + " </value>"
222 + " </ent>"
223 + " <ent>"
224 + " <value>"
225 + " <int>3</int>"
226 + " </value>"
227 + " <value>"
228 + " <int>4</int>"
229 + " </value>"
230 + " </ent>"
231 + "</root>");
232 myDiff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
233 XMLAssert.assertXMLEqual("Not similar", myDiff, true);
234 }
235
236 /**
237 * @see https://sourceforge.net/forum/forum.php?thread_id=2948005&amp;forum_id=73273
238 */
239 public void testOpenDiscussionThread2948995_2() throws Exception {
240 Diff myDiff = new Diff("<root>"
241 + " <ent>"
242 + " <value>"
243 + " <int>1</int>"
244 + " </value>"
245 + " <value>"
246 + " <int>2</int>"
247 + " </value>"
248 + " </ent>"
249 + " <ent>"
250 + " <value>"
251 + " <int>3</int>"
252 + " </value>"
253 + " <value>"
254 + " <int>4</int>"
255 + " </value>"
256 + " </ent>"
257 + "</root>",
258 "<root>"
259 + " <ent>"
260 + " <value>"
261 + " <int>1</int>"
262 + " </value>"
263 + " <value>"
264 + " <int>2</int>"
265 + " </value>"
266 + " </ent>"
267 + " <ent>"
268 + " <value>"
269 + " <int>4</int>"
270 + " </value>"
271 + " <value>"
272 + " <int>3</int>"
273 + " </value>"
274 + " </ent>"
275 + "</root>");
276 myDiff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
277 XMLAssert.assertXMLEqual("Not similar", myDiff, true);
278 }
279 }
0 /*
1 ******************************************************************
2 Copyright (c) 2008, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit.examples;
36
37 import junit.framework.TestCase;
38
39 import org.custommonkey.xmlunit.Diff;
40 import org.custommonkey.xmlunit.Difference;
41 import org.custommonkey.xmlunit.DifferenceListener;
42 import org.w3c.dom.Node;
43
44 public class test_TextDifferenceListenerBase extends TestCase {
45 private static final String C_ATTR = "controlAttr";
46 private static final String T_ATTR = "testAttr";
47 private static final String C_CDATA = "controlCdata";
48 private static final String T_CDATA = "testCdata";
49 private static final String C_CMMT = "controlComment";
50 private static final String T_CMMT = "testComment";
51 private static final String C_TEXT = "controlText";
52 private static final String T_TEXT = "testText";
53
54 public void testTextDifferenceDelegations() throws Exception {
55 final int[] invocations = new int[4];
56
57 String control = getDoc(C_ATTR, C_CDATA, C_CMMT, C_TEXT);
58 String test = getDoc(T_ATTR, T_CDATA, T_CMMT, T_TEXT);
59
60 TextDifferenceListenerBase b = new TextDifferenceListenerBase(null) {
61 protected int attributeDifference(Difference d) {
62 assertEquals(C_ATTR, d.getControlNodeDetail().getValue());
63 assertEquals(T_ATTR, d.getTestNodeDetail().getValue());
64 invocations[0]++;
65 return 1;
66 }
67
68 protected int cdataDifference(Difference d) {
69 assertEquals(C_CDATA, d.getControlNodeDetail().getValue());
70 assertEquals(T_CDATA, d.getTestNodeDetail().getValue());
71 invocations[1]++;
72 return 1;
73 }
74
75 protected int commentDifference(Difference d) {
76 assertEquals(C_CMMT, d.getControlNodeDetail().getValue());
77 assertEquals(T_CMMT, d.getTestNodeDetail().getValue());
78 invocations[2]++;
79 return 1;
80 }
81
82 protected int textDifference(Difference d) {
83 assertEquals(C_TEXT, d.getControlNodeDetail().getValue());
84 assertEquals(T_TEXT, d.getTestNodeDetail().getValue());
85 invocations[3]++;
86 return 1;
87 }
88 };
89
90 Diff d = new Diff(control, test);
91 d.overrideDifferenceListener(b);
92
93 assertTrue(d.identical());
94
95 for (int i = 0; i < invocations.length; i++) {
96 assertEquals(1, invocations[i]);
97 }
98 }
99
100 public void testTextualDifference() throws Exception {
101 final int[] invocations = new int[1];
102
103 String control = getDoc(C_ATTR, C_CDATA, C_CMMT, C_TEXT);
104 String test = getDoc(T_ATTR, T_CDATA, T_CMMT, T_TEXT);
105
106 TextDifferenceListenerBase b = new TextDifferenceListenerBase(null) {
107 protected int textualDifference(Difference d) {
108 invocations[0]++;
109 return 1;
110 }
111 };
112
113 Diff d = new Diff(control, test);
114 d.overrideDifferenceListener(b);
115
116 assertTrue(d.identical());
117 assertEquals(4, invocations[0]);
118 }
119
120 public void testFullDelegation() throws Exception {
121 final int[] invocations = new int[1];
122
123 String control = getDoc(C_ATTR, C_CDATA, C_CMMT, C_TEXT);
124 String test = getDoc(T_ATTR, T_CDATA, T_CMMT, T_TEXT);
125
126 TextDifferenceListenerBase b =
127 new TextDifferenceListenerBase(new DifferenceListener() {
128 public int differenceFound(Difference d) {
129 invocations[0]++;
130 return 1;
131 }
132 public void skippedComparison(Node c, Node t) {
133 fail("skippedComparison shouldn't get invoked");
134 }
135 }) {};
136
137 Diff d = new Diff(control, test);
138 d.overrideDifferenceListener(b);
139
140 assertTrue(d.identical());
141 assertEquals(4, invocations[0]);
142 }
143
144 private static String getDoc(String attr, String cdata, String comment,
145 String text) {
146 return "<root><first attr=\"" + attr + "\"/><!--" + comment + "-->"
147 + "<second><![CDATA[" + cdata + "]]></second><third>" + text
148 + "</third></root>";
149 }
150 }
0 // -*- Mode: JDE -*-
1 /*
2 ******************************************************************
3 Copyright (c) 2001, Jeff Martin, Tim Bacon
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of the xmlunit.sourceforge.net nor the names
17 of its contributors may be used to endorse or promote products
18 derived from this software without specific prior written
19 permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33
34 ******************************************************************
35 */
36 package org.custommonkey.xmlunit.examples;
37
38 public class test_XPathRegexAssert extends junit.framework.TestCase {
39
40 public void testMatch() throws Exception {
41 XPathRegexAssert.assertXPathMatches("\\d", "/foo/text()",
42 "<foo>5</foo>");
43 }
44
45 public void testNoMatch() throws Exception {
46 try {
47 XPathRegexAssert.assertXPathMatches("\\d", "/foo/text()",
48 "<foo>a</foo>");
49 } catch (junit.framework.AssertionFailedError e) {
50 return;
51 }
52 // if we get here, the assertion has passed
53 fail("a is not a number");
54 }
55
56 }
0 /*
1 ******************************************************************
2 Copyright (c) 2006-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import org.custommonkey.xmlunit.AbstractXpathEngineTests;
39 import org.custommonkey.xmlunit.XpathEngine;
40
41 /**
42 * JUnit test for Jaxp13XpathEngine
43 */
44 public class test_Jaxp13XpathEngine extends AbstractXpathEngineTests {
45
46 protected XpathEngine newXpathEngine() {
47 return new Jaxp13XpathEngine();
48 }
49
50 public test_Jaxp13XpathEngine(String name) {
51 super(name);
52 }
53
54 }
55
0 /*
1 ******************************************************************
2 Copyright (c) 2008,2011,2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.util.Iterator;
41 import java.util.List;
42 import javax.xml.transform.stream.StreamSource;
43
44 import junit.framework.TestCase;
45
46 import org.custommonkey.xmlunit.test_Constants;
47 import org.custommonkey.xmlunit.exceptions.XMLUnitRuntimeException;
48 import org.xml.sax.SAXException;
49 import org.xml.sax.SAXParseException;
50
51 public class test_Validator extends TestCase {
52
53 public void testGoodSchemaIsValid() throws Exception {
54 Validator v = new Validator();
55 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
56 + "/tests/etc/Book.xsd")));
57 assertTrue(v.isSchemaValid());
58 }
59
60 public void testGoodSchemaIsValidWithCustomPrefix() throws Exception {
61 Validator v = new Validator();
62 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
63 + "/tests/etc/Book.xsd2")));
64 assertTrue(v.isSchemaValid());
65 }
66
67 public void testGoodSchemaHasNoErrors() throws Exception {
68 Validator v = new Validator();
69 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
70 + "/tests/etc/Book.xsd")));
71 assertEquals(0, v.getSchemaErrors().size());
72 }
73
74 public void testBrokenSchemaIsInvalid() throws Exception {
75 Validator v = new Validator();
76 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
77 + "/tests/etc/broken.xsd")));
78 assertFalse(v.isSchemaValid());
79 }
80
81 public void testBrokenSchemaHasErrors() throws Exception {
82 Validator v = new Validator();
83 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
84 + "/tests/etc/broken.xsd")));
85 List l = v.getSchemaErrors();
86 for (Iterator i = l.iterator(); i.hasNext(); ) {
87 Object ex = i.next();
88 assertTrue(ex instanceof SAXParseException);
89 /*
90 System.err.println(ex);
91 */
92 }
93 assertTrue(l.size() > 0);
94 }
95
96 public void testGoodInstanceIsValid() throws Exception {
97 Validator v = new Validator();
98 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
99 + "/tests/etc/Book.xsd")));
100 StreamSource s =
101 new StreamSource(new File(test_Constants.BASEDIR
102 + "/tests/etc/BookXsdGenerated.xml"));
103 assertTrue(v.isInstanceValid(s));
104 }
105
106 public void testGoodInstanceIsValidNoSchemaSource() throws Exception {
107 Validator v = new Validator();
108 StreamSource s =
109 new StreamSource(new File(test_Constants.BASEDIR
110 + "/tests/etc/BookXsdGeneratedWithFixedSchemaLocation.xml"));
111 assertTrue(v.isInstanceValid(s));
112 }
113
114 public void testBadInstanceIsInvalid() throws Exception {
115 Validator v = new Validator();
116 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
117 + "/tests/etc/Book.xsd")));
118 StreamSource s =
119 new StreamSource(new File(test_Constants.BASEDIR
120 + "/tests/etc/invalidBook.xml"));
121 assertFalse(v.isInstanceValid(s));
122 }
123
124 public void testBadInstanceHasErrors() throws Exception {
125 Validator v = new Validator();
126 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
127 + "/tests/etc/Book.xsd")));
128 StreamSource s =
129 new StreamSource(new File(test_Constants.BASEDIR
130 + "/tests/etc/invalidBook.xml"));
131 List l = v.getInstanceErrors(s);
132 for (Iterator i = l.iterator(); i.hasNext(); ) {
133 Object ex = i.next();
134 assertTrue(ex instanceof SAXParseException);
135 /*
136 System.err.println(ex);
137 */
138 }
139 assertTrue(l.size() > 0);
140 }
141
142 public void testInstanceValidationOfBrokenSchema() {
143 Validator v = new Validator();
144 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
145 + "/tests/etc/broken.xsd")));
146 StreamSource s =
147 new StreamSource(new File(test_Constants.BASEDIR
148 + "/tests/etc/BookXsdGenerated.xml"));
149 try {
150 v.isInstanceValid(s);
151 fail("expected exception because schema is invalid");
152 } catch (XMLUnitRuntimeException e) {
153 assertTrue(e.getCause() instanceof SAXException);
154 }
155 }
156
157 public void testInstanceValidationOfMissingFile() {
158 Validator v = new Validator();
159 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
160 + "/tests/etc/Book.xsd")));
161 StreamSource s =
162 new StreamSource(new File(test_Constants.BASEDIR
163 + "/tests/etc/not there.xml"));
164 try {
165 v.isInstanceValid(s);
166 fail("expected exception because instance doesn't exist");
167 } catch (XMLUnitRuntimeException e) {
168 assertTrue(e.getCause() instanceof IOException);
169 }
170 }
171
172 /**
173 * fails unless you manage to setup JAXP 1.3 and RELAX NG support
174 *
175 * <p>The setup that worked for Stefan when he wrote this test:
176 * JDK 1.5.0_09, isorelax-jaxp-bridge-1.0, together with msv.jar,
177 * isorelax.jar, relaxngDatatype.jar and xsdlib.jar from msv's
178 * latest nightly build (2008-02-13, actually). The same jars do
179 * not work with Java6.</p>
180 *
181 * @see http://weblogs.java.net/blog/kohsuke/archive/2006/02/validate_xml_us.html
182 */
183 public void XtestGoodRelaxNGSchemaIsValid() throws Exception {
184 Validator v = new Validator(javax.xml.XMLConstants.RELAXNG_NS_URI);
185 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
186 + "/tests/etc/Book.rng")));
187 assertTrue(v.isSchemaValid());
188 }
189
190 /**
191 * fails unless you manage to setup JAXP 1.3 and RELAX NG support
192 * @see #XtestGoodRelaxNGSchemaIsValid()
193 */
194 public void XtestGoodInstanceIsValidRNG() throws Exception {
195 Validator v = new Validator(javax.xml.XMLConstants.RELAXNG_NS_URI);
196 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
197 + "/tests/etc/Book.rng")));
198 StreamSource s =
199 new StreamSource(new File(test_Constants.BASEDIR
200 + "/tests/etc/BookXsdGeneratedNoSchema.xml"));
201 assertTrue(v.isInstanceValid(s));
202 }
203
204 /**
205 * fails unless you manage to setup JAXP 1.3 and RELAX NG support
206 * @see #XtestGoodRelaxNGSchemaIsValid()
207 */
208 public void XtestBadInstanceIsInvalidRNG() throws Exception {
209 Validator v = new Validator(javax.xml.XMLConstants.RELAXNG_NS_URI);
210 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
211 + "/tests/etc/Book.rng")));
212 StreamSource s =
213 new StreamSource(new File(test_Constants.BASEDIR
214 + "/tests/etc/invalidBook.xml"));
215 List l = v.getInstanceErrors(s);
216 for (Iterator i = l.iterator(); i.hasNext(); ) {
217 Object ex = i.next();
218 assertTrue(ex instanceof SAXParseException);
219 /*
220 System.err.println(ex);
221 */
222 }
223 assertTrue(l.size() > 0);
224 }
225
226 /**
227 * fails even using the setup in XtestGoodRelaxNGSchemaIsValid()
228 * since a SAXParser is trying to read the compact syntax
229 * definition and chokes on it not being XML.
230 * @see #XtestGoodRelaxNGSchemaIsValid()
231 */
232 public void XtestGoodRelaxNGCompactSyntaxIsValid() throws Exception {
233 Validator v = new Validator(javax.xml.XMLConstants.RELAXNG_NS_URI);
234 v.addSchemaSource(new StreamSource(new File(test_Constants.BASEDIR
235 + "/tests/etc/Book.rngc")));
236 assertTrue(v.isSchemaValid());
237 StreamSource s =
238 new StreamSource(new File(test_Constants.BASEDIR
239 + "/tests/etc/BookXsdGeneratedNoSchema.xml"));
240 assertTrue(v.isInstanceValid(s));
241 }
242
243 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.jaxp13;
37
38 import org.custommonkey.xmlunit.NamespaceContext;
39 import org.custommonkey.xmlunit.SimpleNamespaceContext;
40
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import javax.xml.XMLConstants;
44
45 import junit.framework.TestCase;
46
47 /**
48 * JUnit test for XMLUnitNamespaceContext2Jaxp13
49 */
50 public class test_XMLUnitNamespaceContext2Jaxp13 extends TestCase {
51 private static final String[] PREFIXES = {"foo", "bar"};
52 private static final String[] STANDARD_PREFIXES = {
53 XMLConstants.XML_NS_PREFIX, XMLConstants.XMLNS_ATTRIBUTE
54 };
55 private static final String[] STANDARD_URIS = {
56 XMLConstants.XML_NS_URI, XMLConstants.XMLNS_ATTRIBUTE_NS_URI
57 };
58 private static final String URI = "urn:example";
59
60 public void testBasics() {
61 XMLUnitNamespaceContext2Jaxp13 ctx =
62 new XMLUnitNamespaceContext2Jaxp13(new SimpleNamespaceContext(setupMap()));
63 validate(ctx);
64 }
65
66 public void testCannotOverrideStandardPrefixes() {
67 HashMap m = setupMap();
68 for (int i = 0; i < STANDARD_PREFIXES.length; i++) {
69 m.put(STANDARD_PREFIXES[i], URI);
70 }
71 XMLUnitNamespaceContext2Jaxp13 ctx =
72 new XMLUnitNamespaceContext2Jaxp13(new SimpleNamespaceContext(m));
73 validate(ctx);
74 }
75
76 public void testCannotOverrideStandardURIs() {
77 HashMap m = setupMap();
78 for (int i = 0; i < STANDARD_PREFIXES.length; i++) {
79 m.put(STANDARD_PREFIXES[i] + "1", STANDARD_URIS[i]);
80 }
81 XMLUnitNamespaceContext2Jaxp13 ctx =
82 new XMLUnitNamespaceContext2Jaxp13(new SimpleNamespaceContext(m));
83 validate(ctx);
84 }
85
86 public void testDefaultNamespaceHandling() {
87 HashMap m = setupMap();
88 m.put("", URI);
89 XMLUnitNamespaceContext2Jaxp13 ctx =
90 new XMLUnitNamespaceContext2Jaxp13(new SimpleNamespaceContext(m));
91
92 // no matter how many prefixes map to it, DEFAULT_NS must be
93 // the first prefix
94 assertEquals(XMLConstants.DEFAULT_NS_PREFIX, ctx.getPrefix(URI));
95
96 Iterator it = ctx.getPrefixes(URI);
97 assertTrue(it.hasNext());
98 assertEquals(XMLConstants.DEFAULT_NS_PREFIX, it.next());
99 assertAllPrefixesFound(it);
100 }
101
102 private static HashMap setupMap() {
103 HashMap map = new HashMap();
104 for (int i = 0; i < PREFIXES.length; i++) {
105 map.put(PREFIXES[i], URI);
106 }
107 return map;
108 }
109
110 private static void validate(XMLUnitNamespaceContext2Jaxp13 ctx) {
111 for (int i = 0; i < PREFIXES.length; i++) {
112 assertEquals(URI, ctx.getNamespaceURI(PREFIXES[i]));
113 }
114 for (int i = 0; i < STANDARD_PREFIXES.length; i++) {
115 assertEquals(STANDARD_URIS[i],
116 ctx.getNamespaceURI(STANDARD_PREFIXES[i]));
117 }
118 assertEquals(XMLConstants.NULL_NS_URI,
119 ctx.getNamespaceURI(PREFIXES[0] + PREFIXES[0]));
120 assertEquals(XMLConstants.NULL_NS_URI,
121 ctx.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
122
123 boolean foundThisPrefix = false;
124 String prefix = ctx.getPrefix(URI);
125 for (int i = 0; !foundThisPrefix && i < PREFIXES.length; i++) {
126 if (PREFIXES[i].equals(prefix)) {
127 foundThisPrefix = true;
128 }
129 }
130 assertTrue("getPrefix returned a known prefix for " + URI,
131 foundThisPrefix);
132 for (int i = 0; i < STANDARD_PREFIXES.length; i++) {
133 assertEquals(STANDARD_PREFIXES[i], ctx.getPrefix(STANDARD_URIS[i]));
134 }
135
136 assertAllPrefixesFound(ctx.getPrefixes(URI));
137 for (int i = 0; i < STANDARD_PREFIXES.length; i++) {
138 Iterator it = ctx.getPrefixes(STANDARD_URIS[i]);
139 assertTrue("One element for " + STANDARD_URIS[i], it.hasNext());
140 assertEquals(STANDARD_PREFIXES[i], it.next());
141 assertFalse("Only one element for " + STANDARD_URIS[i],
142 it.hasNext());
143 }
144
145 assertNull(ctx.getPrefix(URI + URI));
146 assertFalse(ctx.getPrefixes(URI + URI).hasNext());
147 }
148
149 private static void assertAllPrefixesFound(Iterator it) {
150 boolean[] found = new boolean[PREFIXES.length];
151 int count = 0;
152 while (it.hasNext()) {
153 count++;
154 String p = (String) it.next();
155 boolean foundThisPrefix = false;
156 for (int i = 0; !foundThisPrefix && i < PREFIXES.length; i++) {
157 if (PREFIXES[i].equals(p)) {
158 found[i] = foundThisPrefix = true;
159 }
160 }
161 if (!foundThisPrefix) {
162 fail("Prefix " + p + " should not be in this context");
163 }
164 }
165 assertEquals(PREFIXES.length, count);
166 for (int i = 0; i < PREFIXES.length; i++) {
167 assertTrue("Context contained " + PREFIXES[i], found[i]);
168 }
169 }
170 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import junit.framework.Assert;
39 import junit.framework.TestCase;
40
41 import org.w3c.dom.CDATASection;
42 import org.w3c.dom.Comment;
43 import org.w3c.dom.DocumentType;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.Entity;
46 import org.w3c.dom.EntityReference;
47 import org.w3c.dom.Node;
48 import org.w3c.dom.Notation;
49 import org.w3c.dom.ProcessingInstruction;
50 import org.w3c.dom.Text;
51
52 /**
53 * JUnit test for AbstractNodeTester
54 */
55 public class test_AbstractNodeTester extends TestCase {
56
57 public void testExactlyOncePerMethod() throws Exception {
58 String testXml = "<!DOCTYPE foo ["
59 + "<!ELEMENT foo (#PCDATA)>"
60 + "<!ATTLIST foo attr CDATA #IMPLIED>"
61 + "<!ENTITY my \"hello\">"
62 + "<!NOTATION notation PUBLIC \"pub\">"
63 + "]>"
64 + "<foo attr=\"value\">"
65 + "<!--comment-->"
66 + "<?target processing-instruction?>"
67 + "bar"
68 + "&my;"
69 + "<![CDATA[baz]]>"
70 + "</foo>";
71 NodeTest nt = new NodeTest(testXml);
72 ExactlyOncePerMethod tester = new ExactlyOncePerMethod();
73 nt.performTest(tester, new short[] {
74 Node.ATTRIBUTE_NODE,
75 Node.CDATA_SECTION_NODE,
76 Node.COMMENT_NODE,
77 Node.DOCUMENT_FRAGMENT_NODE,
78 Node.DOCUMENT_NODE,
79 Node.DOCUMENT_TYPE_NODE,
80 Node.ELEMENT_NODE,
81 Node.ENTITY_NODE,
82 Node.ENTITY_REFERENCE_NODE,
83 Node.NOTATION_NODE,
84 Node.PROCESSING_INSTRUCTION_NODE,
85 Node.TEXT_NODE,
86 });
87 tester.verify();
88 }
89
90 private class ExactlyOncePerMethod extends AbstractNodeTester {
91
92 private boolean cdataCalled;
93 private boolean commentCalled;
94 private boolean elementCalled;
95 private boolean piCalled;
96 private boolean textCalled;
97 private boolean noMoreNodesCalled;
98
99 public void testCDATASection(CDATASection cdata) {
100 Assert.assertFalse("testCDATASection called", cdataCalled);
101 cdataCalled = true;
102 Assert.assertEquals("baz", cdata.getNodeValue());
103 }
104
105 public void testComment(Comment comment) {
106 Assert.assertFalse("testComment called", commentCalled);
107 commentCalled = true;
108 Assert.assertEquals("comment", comment.getNodeValue());
109 }
110
111 public void testElement(Element element) {
112 Assert.assertFalse("testElement called", elementCalled);
113 elementCalled = true;
114 Assert.assertEquals("foo", element.getNodeName());
115 Assert.assertEquals("value", element.getAttribute("attr"));
116 }
117
118 public void testProcessingInstruction(ProcessingInstruction instr) {
119 Assert.assertFalse("testProcessingInstruction called", piCalled);
120 piCalled = true;
121 Assert.assertEquals("target", instr.getTarget());
122 Assert.assertEquals("processing-instruction", instr.getData());
123 }
124
125 public void testText(Text text) {
126 Assert.assertFalse("testText called", textCalled);
127 textCalled = true;
128 Assert.assertEquals("barhello", text.getNodeValue());
129 }
130
131 public void noMoreNodes(NodeTest t) {
132 Assert.assertFalse("noMoreNodes called", noMoreNodesCalled);
133 noMoreNodesCalled = true;
134 }
135
136 void verify() {
137 Assert.assertTrue("testCDATASection not called", cdataCalled);
138 Assert.assertTrue("testComment not called", commentCalled);
139 Assert.assertTrue("testElement not called", elementCalled);
140 Assert.assertTrue("testProcessingInstruction not called",
141 piCalled);
142 Assert.assertTrue("testText not called", textCalled);
143 Assert.assertTrue("noMoreNodes not called", noMoreNodesCalled);
144 }
145 }
146 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import junit.framework.TestCase;
39 import junit.framework.TestSuite;
40
41 /**
42 * Regression test class for various bug fixes
43 */
44 public class test_BugFixes extends TestCase {
45 public void setUp() throws Exception {
46 XMLUnit.setControlParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
47 XMLUnit.setTestParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
48 XMLUnit.setSAXParserFactory("org.apache.xerces.jaxp.SAXParserFactoryImpl");
49 XMLUnit.setTransformerFactory("org.apache.xalan.processor.TransformerFactoryImpl");
50 }
51
52 /**
53 * Return the test suite containing the bug fix tests
54 */
55 public static TestSuite suite() {
56 TestSuite suite = new TestSuite();
57 suite.addTest(new test_XMLUnit("testStripWhitespaceTransform"));
58 suite.addTest(new test_Diff("testXMLUnitDoesNotWorkWellWithFiles"));
59 suite.addTest(new test_Transform("testXSLIncludeWithoutSystemId"));
60 suite.addTest(new test_Diff("testNamespaceIssues"));
61 suite.addTest(new test_Diff("testDefaultNamespace"));
62 suite.addTest(new test_DetailedDiff("testLargeFiles"));
63 suite.addTest(new test_DetailedDiff("testDifferentStructure"));
64 suite.addTest(new test_Diff("testXMLNSNumberOfAttributes"));
65 return suite;
66 }
67 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import junit.framework.TestCase;
39 import junit.framework.TestSuite;
40
41 /**
42 * Not actually a test container, but conforms to the semantics
43 */
44 public class test_Constants extends TestCase
45 implements XMLConstants, XSLTConstants {
46 static {
47 if (System.getProperty("basedir")==null) {
48 System.setProperty("basedir", "d:/projects/sourceforge/xmlunit");
49 }
50 }
51
52 public static final String BASEDIR = System.getProperty("basedir");
53 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
54
55 public static final String CHUCK_JONES_RIP_DTD =
56 "<!ELEMENT name (#PCDATA)> \n"
57 + "<!ELEMENT toon (name)> \n"
58 + "<!ELEMENT cartoons (toon*)> \n";
59
60 public static final String CHUCK_JONES_RIP_DTD_DECL =
61 "<!DOCTYPE cartoons ["
62 + CHUCK_JONES_RIP_DTD + "\n]>";
63
64 private static final String DOCUMENT_START = "<cartoons>";
65 private static final String DOCUMENT_END = "</cartoons>";
66
67 public static final String CHUCK_JONES_RIP_XML = DOCUMENT_START
68 + "<toon><name>bugs bunny</name></toon>"
69 + "<!--meep meep--><toon><name>roadrunnner</name></toon>"
70 + DOCUMENT_END;
71
72 public static final String EXTERNAL_DTD = BASEDIR + "/cartoons.dtd";
73
74 public static final String DOCUMENT_WITH_GOOD_EXTERNAL_DTD =
75 "<!DOCTYPE cartoons SYSTEM \"yak.dtd\">"
76 + CHUCK_JONES_RIP_XML;
77 public static final String DOCUMENT_WITH_NO_EXTERNAL_DTD =
78 CHUCK_JONES_RIP_XML;
79
80 public static final String CHUCK_JONES_SPINNING_IN_HIS_GRAVE_XML =
81 DOCUMENT_START + "<kidsTv><toon><name>Yo ho ahoy</name></toon></kidsTV>"
82 + DOCUMENT_END;
83
84 public static final String XML_WITH_WHITESPACE =
85 "<aakture> <node>text</node>\t<node>text2</node> \n </aakture>";
86
87 public static final String XML_WITHOUT_WHITESPACE =
88 "<aakture><node>text</node><node>text2</node></aakture>";
89
90 public test_Constants(String name) {
91 super(name);
92 }
93
94 /**
95 * Return an empty test suite as this pseudo test class has no tests
96 */
97 public static TestSuite suite() {
98 return new TestSuite();
99 }
100 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008,2010,2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileReader;
40 import java.io.Reader;
41 import java.util.Iterator;
42 import java.util.List;
43
44 import org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier;
45 import org.w3c.dom.Document;
46 import org.xml.sax.InputSource;
47
48 /**
49 * Test a DetailedDiff. Extend the test case class for Diff so we can rerun those
50 * tests with a DetailedDiff and assert that behaviour has not changed.
51 */
52 public class test_DetailedDiff extends test_Diff {
53 private String firstForecast, secondForecast;
54
55 public void testAllDifferencesFirstForecastControl() throws Exception {
56 Diff multipleDifferences = new Diff(firstForecast, secondForecast);
57 DetailedDiff detailedDiff = new DetailedDiff(multipleDifferences);
58
59 List differences = detailedDiff.getAllDifferences();
60 assertExpectedDifferencesFirstForecastControl(differences, detailedDiff);
61 }
62
63 private void assertExpectedDifferencesFirstForecastControl(List differences,
64 DetailedDiff detailedDiff) {
65 assertEquals("size: " + detailedDiff, 7, differences.size());
66 assertEquals("first: " + detailedDiff,
67 DifferenceConstants.ELEMENT_NUM_ATTRIBUTES, differences.get(0));
68 assertEquals("second: " + detailedDiff,
69 DifferenceConstants.ATTR_NAME_NOT_FOUND, differences.get(1));
70 assertEquals("third: " + detailedDiff,
71 DifferenceConstants.ATTR_VALUE, differences.get(2));
72 assertEquals("fourth: " + detailedDiff,
73 DifferenceConstants.ATTR_SEQUENCE, differences.get(3));
74 assertEquals("fifth: " + detailedDiff,
75 DifferenceConstants.HAS_CHILD_NODES, differences.get(4));
76 assertEquals("sixth: " + detailedDiff,
77 DifferenceConstants.CHILD_NODELIST_LENGTH, differences.get(5));
78 assertEquals("seventh: " + detailedDiff,
79 DifferenceConstants.CHILD_NODE_NOT_FOUND, differences.get(6));
80 }
81
82 public void testAllDifferencesSecondForecastControl() throws Exception {
83 Diff multipleDifferences = new Diff(secondForecast, firstForecast);
84 DetailedDiff detailedDiff = new DetailedDiff(multipleDifferences);
85
86 List differences = detailedDiff.getAllDifferences();
87
88 assertEquals("size: " + detailedDiff, 7, differences.size());
89 assertEquals("first: " + detailedDiff,
90 DifferenceConstants.ELEMENT_NUM_ATTRIBUTES, differences.get(0));
91 assertEquals("second: " + detailedDiff,
92 DifferenceConstants.ATTR_VALUE, differences.get(1));
93 assertEquals("third: " + detailedDiff,
94 DifferenceConstants.ATTR_SEQUENCE, differences.get(2));
95 assertEquals("forth: " + detailedDiff,
96 DifferenceConstants.ATTR_NAME_NOT_FOUND,
97 differences.get(3));
98 assertEquals("fifth: " + detailedDiff,
99 DifferenceConstants.HAS_CHILD_NODES, differences.get(4));
100 assertEquals("sixth: " + detailedDiff,
101 DifferenceConstants.CHILD_NODELIST_LENGTH, differences.get(5));
102 assertEquals("seventy: " + detailedDiff,
103 DifferenceConstants.CHILD_NODE_NOT_FOUND, differences.get(6));
104 }
105
106 public void testPrototypeIsADetailedDiff() throws Exception {
107 Diff multipleDifferences = new Diff(firstForecast, secondForecast);
108 DetailedDiff detailedDiff = new DetailedDiff(
109 new DetailedDiff(multipleDifferences));
110
111 List differences = detailedDiff.getAllDifferences();
112 assertExpectedDifferencesFirstForecastControl(differences, detailedDiff);
113 }
114
115 public void testLargeFiles() throws Exception {
116 int i = 0;
117 String expr = null;
118 File test, control;
119 control = new File(test_Constants.BASEDIR + "/tests/etc/controlDetail.xml");
120 test = new File(test_Constants.BASEDIR + "/tests/etc/testDetail.xml");
121 DetailedDiff differencesWithWhitespace = new DetailedDiff(
122 new Diff(new InputSource(new FileReader(control)),
123 new InputSource(new FileReader(test))) );
124
125 List l = differencesWithWhitespace.getAllDifferences();
126 int unmatchedNodeDiffs = 0;
127 int hasChildNodeDiffs = 0;
128 for (Iterator iter = l.iterator(); iter.hasNext();) {
129 Difference d = (Difference) iter.next();
130 if (d.getId() == DifferenceConstants.CHILD_NODE_NOT_FOUND_ID) {
131 unmatchedNodeDiffs++;
132 } else if (d.getId() == DifferenceConstants.HAS_CHILD_NODES_ID) {
133 hasChildNodeDiffs++;
134 }
135 }
136
137 assertEquals(1402 + hasChildNodeDiffs + unmatchedNodeDiffs,
138 differencesWithWhitespace.getAllDifferences().size());
139
140 try {
141 XMLUnit.setIgnoreWhitespace(true);
142 Diff prototype =
143 new Diff(new FileReader(control), new FileReader(test));
144 DetailedDiff detailedDiff = new DetailedDiff(prototype);
145 List differences = detailedDiff.getAllDifferences();
146 unmatchedNodeDiffs = 0;
147 hasChildNodeDiffs = 0;
148 for (Iterator iter = differences.iterator(); iter.hasNext();) {
149 Difference d = (Difference) iter.next();
150 if (d.getId() == DifferenceConstants.CHILD_NODE_NOT_FOUND_ID) {
151 unmatchedNodeDiffs++;
152 } else if (d.getId() == DifferenceConstants.HAS_CHILD_NODES_ID) {
153 hasChildNodeDiffs++;
154 }
155 }
156 assertEquals(40 + hasChildNodeDiffs + unmatchedNodeDiffs, differences.size());
157
158 SimpleXpathEngine xpathEngine = new SimpleXpathEngine();
159 Document controlDoc =
160 XMLUnit.buildControlDocument(
161 new InputSource(new FileReader(control)));
162 Document testDoc =
163 XMLUnit.buildTestDocument(
164 new InputSource(new FileReader(test)));
165
166 Difference aDifference;
167 String value;
168 for (Iterator iter = differences.iterator(); iter.hasNext();) {
169 aDifference = (Difference) iter.next();
170 if (aDifference.equals(DifferenceConstants.ATTR_VALUE)
171 || aDifference.equals(DifferenceConstants.CDATA_VALUE)
172 || aDifference.equals(DifferenceConstants.COMMENT_VALUE)
173 || aDifference.equals(DifferenceConstants.ELEMENT_TAG_NAME)
174 || aDifference.equals(DifferenceConstants.TEXT_VALUE)) {
175 expr = aDifference.getControlNodeDetail().getXpathLocation();
176 if (expr==null || expr.length()==0) {
177 System.out.println(aDifference);
178 } else {
179 value = xpathEngine.evaluate(expr, controlDoc);
180 assertEquals(i + " control " + aDifference.toString(),
181 value, aDifference.getControlNodeDetail().getValue());
182 }
183
184 expr = aDifference.getTestNodeDetail().getXpathLocation();
185 if (expr == null || expr.length()==0) {
186 System.out.println(aDifference);
187 } else {
188 value = xpathEngine.evaluate(expr, testDoc);
189 assertEquals(i + " test " + aDifference.toString(),
190 value, aDifference.getTestNodeDetail().getValue());
191 }
192 }
193 ++i;
194 }
195 } catch (Exception e) {
196 System.out.println("eek@" + i + ":" + expr);
197 throw e;
198 } finally {
199 XMLUnit.setIgnoreWhitespace(false);
200 }
201
202 }
203
204 public void testSeeAllDifferencesEvenIfDiffWouldSayHaltComparison() throws Exception {
205 String control = "<a><b/><c/></a>";
206 String test = "<a><c/></a>";
207
208 Diff d = new Diff(control, test);
209 DetailedDiff dd = new DetailedDiff(d);
210
211 List l = dd.getAllDifferences();
212 // number of children is different, didn't find <b/>, wrong
213 // sequence of nodes
214 assertEquals(3, l.size());
215 }
216
217 public void testSeeAllDifferencesEvenIfDiffSaysHaltComparison() throws Exception {
218 String control = "<a><b/><c/></a>";
219 String test = "<a><c/></a>";
220
221 Diff d = new Diff(control, test);
222 d.similar();
223 DetailedDiff dd = new DetailedDiff(d);
224
225 List l = dd.getAllDifferences();
226 // number of children is different, didn't find <b/>, wrong
227 // sequence of nodes
228 assertEquals(3, l.size());
229 }
230
231 /**
232 * @see http://sourceforge.net/forum/forum.php?thread_id=1691528&forum_id=73274
233 */
234 public void testHelpForumThread1691528() throws Exception {
235 String control = "<table border=\"1\">"
236 + "<tr>"
237 + "<th>News</th>"
238 + "</tr>"
239 + "<tr>"
240 + "<td>Newsitem 1</td>"
241 + "</tr>"
242 + "</table>";
243 String test = "<table border=\"1\">"
244 + "<tr>"
245 + "<th>News</th>"
246 + "</tr>"
247 + "<tr>"
248 + "<td>Newsitem 2</td>"
249 + "<td>Newsitem 1</td>"
250 + "</tr>"
251 + "</table>";
252
253 DetailedDiff diff = new DetailedDiff(new Diff(control, test));
254 List changes = diff.getAllDifferences();
255 // number of children, text of first child, unexpected second
256 // test child
257 assertEquals(3, changes.size());
258 }
259
260 /**
261 * Bug 1860681
262 * @see https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1860681&amp;group_id=23187&amp;atid=377768
263 */
264 public void testXpathOfMissingNode() throws Exception {
265 String control =
266 "<books>"
267 + " <book>"
268 + " <title>Kabale und Liebe</title>"
269 + " </book>"
270 + " <book>"
271 + " <title>Schuld und Suehne</title>"
272 + " </book>"
273 + "</books>";
274 String test =
275 "<books>"
276 + " <book>"
277 + " <title>Schuld und Suehne</title>"
278 + " </book>"
279 + "</books>";
280 XMLUnit.setIgnoreWhitespace(true);
281 try {
282 Diff diff = new Diff(control, test);
283 diff.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2));
284 DetailedDiff dd = new DetailedDiff(diff);
285 List l = dd.getAllDifferences();
286 assertEquals(3, l.size());
287 // (0) number of children, (1) node not found, (2) order different
288 Difference d = (Difference) l.get(1);
289 assertEquals(DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
290 d.getId());
291 assertEquals("/books[1]/book[1]",
292 d.getControlNodeDetail().getXpathLocation());
293 assertNull("should be null but is "
294 + d.getTestNodeDetail().getXpathLocation(),
295 d.getTestNodeDetail().getXpathLocation());
296
297 // and reverse
298 diff = new Diff(test, control);
299 diff.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(2));
300 dd = new DetailedDiff(diff);
301 l = dd.getAllDifferences();
302 assertEquals(3, l.size());
303 // (0) number of children, (1) order different, (2) node not found
304 d = (Difference) l.get(2);
305 assertEquals(DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
306 d.getId());
307 assertEquals("/books[1]/book[1]",
308 d.getTestNodeDetail().getXpathLocation());
309 assertNull(d.getControlNodeDetail().getXpathLocation());
310 } finally {
311 XMLUnit.setIgnoreWhitespace(false);
312 }
313 }
314
315 protected Diff buildDiff(Document control, Document test) {
316 return new DetailedDiff(super.buildDiff(control, test));
317 }
318
319 protected Diff buildDiff(String control, String test) throws Exception {
320 return new DetailedDiff(super.buildDiff(control, test));
321 }
322
323 protected Diff buildDiff(Reader control, Reader test) throws Exception {
324 return new DetailedDiff(super.buildDiff(control, test));
325 }
326
327 protected Diff buildDiff(String control, String test,
328 DifferenceEngine engine) throws Exception {
329 return new DetailedDiff(super.buildDiff(control, test, engine));
330 }
331
332 public test_DetailedDiff(String name) {
333 super(name);
334 firstForecast = "<weather><today icon=\"clouds\" temp=\"17\">"
335 + "<outlook>unsettled</outlook></today></weather>";
336 secondForecast = "<weather><today temp=\"20\"/></weather>";
337 }
338
339 /**
340 * https://sourceforge.net/tracker/?func=detail&aid=2758280&group_id=23187&atid=377768
341 */
342 public void testCompareUnmatched() throws Exception {
343 String control = "<root><a>1</a>"
344 + "<b>1</b>"
345 + "<c>1</c>"
346 + "<d>1</d>"
347 + "<e>1</e></root>";
348 String test = "<root><a>1</a>"
349 + "<b>1</b>"
350 + "<z>1</z>"
351 + "<d>1</d>"
352 + "<e>1</e></root>";
353 DetailedDiff d = (DetailedDiff) buildDiff(control, test);
354 List l = d.getAllDifferences();
355 assertEquals(1, l.size());
356 Difference diff = (Difference) l.get(0);
357 assertEquals(DifferenceConstants.ELEMENT_TAG_NAME_ID, diff.getId());
358 }
359
360 /**
361 * https://sourceforge.net/tracker/?func=detail&aid=2758280&group_id=23187&atid=377768
362 */
363 public void testDontCompareUnmatched() throws Exception {
364 String control = "<root><a>1</a>"
365 + "<b>1</b>"
366 + "<c>1</c>"
367 + "<d>1</d>"
368 + "<e>1</e></root>";
369 String test = "<root><a>1</a>"
370 + "<b>1</b>"
371 + "<z>1</z>"
372 + "<d>1</d>"
373 + "<e>1</e></root>";
374 try {
375 XMLUnit.setCompareUnmatched(false);
376 DetailedDiff d = (DetailedDiff) buildDiff(control, test);
377 List l = d.getAllDifferences();
378 assertEquals(2, l.size());
379 Difference diff = (Difference) l.get(0);
380 assertEquals(DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
381 diff.getId());
382 assertNotNull(diff.getControlNodeDetail().getNode());
383 assertNull(diff.getTestNodeDetail().getNode());
384 diff = (Difference) l.get(1);
385 assertEquals(DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
386 diff.getId());
387 assertNull(diff.getControlNodeDetail().getNode());
388 assertNotNull(diff.getTestNodeDetail().getNode());
389 } finally {
390 XMLUnit.setCompareUnmatched(true);
391 }
392 }
393
394 /**
395 * @see https://sourceforge.net/tracker/index.php?func=detail&amp;aid=3062518&amp;group_id=23187&amp;atid=377768
396 */
397 public void testIssue3062518() throws Exception {
398 String control = "<Fruits>"
399 + "<Apple size=\"11\" color=\"green\"/>"
400 + "<Apple size=\"15\" color=\"green\"/>"
401 + "<Banana size=\"10\"/>"
402 + "</Fruits>";
403 String test = "<Fruits>"
404 + "<Apple size=\"11\" color=\"green\"/>"
405 + "<Banana size=\"11\"/>"
406 + "</Fruits>";
407 try {
408 XMLUnit.setCompareUnmatched(false);
409 DetailedDiff d = (DetailedDiff) buildDiff(control, test);
410 List l = d.getAllDifferences();
411 assertEquals(4, l.size());
412 // expected 3 children is 2
413 Difference diff = (Difference) l.get(0);
414 assertEquals(DifferenceConstants.CHILD_NODELIST_LENGTH_ID,
415 diff.getId());
416 assertEquals("3", diff.getControlNodeDetail().getValue());
417 assertEquals("2", diff.getTestNodeDetail().getValue());
418 assertEquals("/Fruits[1]",
419 diff.getControlNodeDetail().getXpathLocation());
420 assertEquals("/Fruits[1]",
421 diff.getTestNodeDetail().getXpathLocation());
422
423 // didn't find the second Apple element
424 diff = (Difference) l.get(1);
425 assertEquals(DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
426 diff.getId());
427 assertEquals("Apple", diff.getControlNodeDetail().getValue());
428 assertEquals("null", diff.getTestNodeDetail().getValue());
429 assertEquals("/Fruits[1]/Apple[2]",
430 diff.getControlNodeDetail().getXpathLocation());
431 assertEquals(null,
432 diff.getTestNodeDetail().getXpathLocation());
433
434 // Banana's size attribute doesn't match
435 diff = (Difference) l.get(2);
436 assertEquals(DifferenceConstants.ATTR_VALUE_ID,
437 diff.getId());
438 assertEquals("10", diff.getControlNodeDetail().getValue());
439 assertEquals("11", diff.getTestNodeDetail().getValue());
440 assertEquals("/Fruits[1]/Banana[1]/@size",
441 diff.getControlNodeDetail().getXpathLocation());
442 assertEquals("/Fruits[1]/Banana[1]/@size",
443 diff.getTestNodeDetail().getXpathLocation());
444
445 // Banana is the third child in control but the second one in test
446 diff = (Difference) l.get(3);
447 assertEquals("2", diff.getControlNodeDetail().getValue());
448 assertEquals("1", diff.getTestNodeDetail().getValue());
449 assertEquals("/Fruits[1]/Banana[1]",
450 diff.getControlNodeDetail().getXpathLocation());
451 assertEquals("/Fruits[1]/Banana[1]",
452 diff.getTestNodeDetail().getXpathLocation());
453 } finally {
454 XMLUnit.setCompareUnmatched(true);
455 }
456 }
457 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2013, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileReader;
40 import java.io.FileWriter;
41 import java.io.Reader;
42 import java.util.HashSet;
43 import java.util.Set;
44
45 import junit.framework.TestCase;
46
47 import org.w3c.dom.Document;
48 import org.w3c.dom.Element;
49 import org.w3c.dom.Node;
50 import org.w3c.dom.Text;
51
52 /**
53 * Test a Diff
54 */
55 public class test_Diff extends TestCase{
56 private static final String[] control = new String[]{
57 "<test/>",
58 "<test></test>",
59 "<test>test</test>",
60 "<test test=\"test\">test</test>",
61 "<test/>",
62 "<test>test</test>",
63 "<test test=\"test\"/>",
64 "<test><test><test></test></test></test>",
65 "<test test=\"test\"><test>test<test>test</test></test></test>",
66 "<test test=\"test\"><test>test<test>test</test></test></test>",
67 "<html>Yo this is a test!</html>",
68 "<java></java>"
69 };
70 private static final String[] test = new String[]{
71 "<fail/>",
72 "<fail/>",
73 "<fail>test</fail>",
74 "<test>test</test>",
75 "<fail/>",
76 "<test>fail</test>",
77 "<test test=\"fail\"/>",
78 "<test><test><test>test</test></test></test>",
79 "<test test=\"test\"><test>fail<test>test</test></test></test>",
80 "<test test=\"fail\"><test>test<test>test</test></test></test>",
81 "<html>Yo this isn't a test!</html>",
82 "<java><package-def><ident>org</ident><dot/><ident>apache</ident><dot/><ident>test</ident></package-def></java>"
83 };
84 private Document aDocument;
85
86 public void setUp() throws Exception {
87 aDocument = XMLUnit.newControlParser().newDocument();
88 }
89
90 public void testToString(){
91 Diff diff = buildDiff(aDocument, aDocument);
92 String[] animals = {"Monkey", "Chicken"};
93 String tag = "tag";
94 Element elemA = aDocument.createElement(tag);
95 Text textA = aDocument.createTextNode(animals[0]);
96 elemA.appendChild(textA);
97
98 Element elemB = aDocument.createElement(tag);
99 Difference difference = new Difference(DifferenceConstants.HAS_CHILD_NODES,
100 new NodeDetail(Boolean.TRUE.toString(), elemA, "/tag"),
101 new NodeDetail(Boolean.FALSE.toString(),elemB, "/tag"));
102 diff.differenceFound(difference);
103
104 assertEquals(diff.getClass().getName() +"\n[different] Expected "
105 + DifferenceConstants.HAS_CHILD_NODES.getDescription()
106 + " 'true' but was 'false' - comparing <tag...> at /tag to <tag...> at /tag\n",
107 diff.toString());
108
109 diff = buildDiff(aDocument, aDocument);
110 Text textB = aDocument.createTextNode(animals[1]);
111 elemB.appendChild(textB);
112 difference = new Difference(DifferenceConstants.TEXT_VALUE,
113 new NodeDetail(animals[0], textA, "/tag/text()"),
114 new NodeDetail(animals[1], textB, "/tag/text()"));
115 diff.differenceFound(difference);
116
117 assertEquals(diff.getClass().getName() +"\n[different] Expected "
118 + DifferenceConstants.TEXT_VALUE.getDescription()
119 + " 'Monkey' but was 'Chicken' - comparing <tag ...>Monkey</tag> "
120 + "at /tag/text() to <tag ...>Chicken</tag> at /tag/text()\n",
121 diff.toString());
122
123 }
124
125 /**
126 * Tests the compare method
127 */
128 public void testSimilar() throws Exception {
129 for(int i=0;i<control.length;i++){
130 assertEquals("XMLUnit.compare().similar() test case "+i+" failed",
131 true, buildDiff(control[i], control[i]).similar());
132 assertEquals("!XMLUnit.compare().similar() test case "+i+" failed",
133 false, (buildDiff(control[i], test[i])).similar());
134 }
135 }
136
137 public void testIdentical() throws Exception {
138 String control="<control><test>test1</test><test>test2</test></control>";
139 String test="<control><test>test2</test><test>test1</test></control>";
140
141 assertEquals("Documents are identical, when they are not", false,
142 buildDiff(control, test).identical());
143 }
144
145 public void testFiles() throws Exception {
146 FileReader control = new FileReader(test_Constants.BASEDIR
147 + "/tests/etc/test.blame.html");
148 FileReader test = new FileReader(test_Constants.BASEDIR
149 + "/tests/etc/test.blame.html");
150 Diff diff = buildDiff(control, test);
151 assertEquals(diff.toString(), true, diff.identical());
152 }
153
154 public void testSameTwoStrings() throws Exception {
155 Diff diff = buildDiff("<same>pass</same>", "<same>pass</same>");
156 assertEquals("same should be identical", true, diff.identical());
157 assertEquals("same should be similar", true, diff.similar());
158 }
159
160 public void testMissingElement() throws Exception {
161 Diff diff = buildDiff("<root></root>", "<root><node/></root>");
162 assertEquals("should not be identical", false, diff.identical());
163 assertEquals("and should not be similar", false, diff.similar());
164 }
165
166 public void testExtraElement() throws Exception {
167 Diff diff = buildDiff("<root><node/></root>", "<root></root>");
168 assertEquals("should not be identical", false, diff.identical());
169 assertEquals("and should not be similar", false, diff.similar());
170 }
171
172 public void testElementsInReverseOrder() throws Exception {
173 Diff diff = buildDiff("<root><same/><pass/></root>", "<root><pass/><same/></root>");
174 assertEquals("should not be identical", false, diff.identical());
175 assertEquals("but should be similar", true, diff.similar());
176 }
177
178 public void testMissingAttribute() throws Exception {
179 Diff diff = buildDiff("<same>pass</same>", "<same except=\"this\">pass</same>");
180 assertEquals("should not be identical", false, diff.identical());
181 assertEquals("and should not be similar", false, diff.similar());
182 }
183
184 public void testExtraAttribute() throws Exception {
185 Diff diff = buildDiff("<same except=\"this\">pass</same>", "<same>pass</same>");
186 assertEquals("should not be identical", false, diff.identical());
187 assertEquals("and should not be similar", false, diff.similar());
188 }
189
190 public void testAttributesInReverseOrder() throws Exception {
191 Diff diff = buildDiff("<same zzz=\"qwerty\" aaa=\"uiop\">pass</same>",
192 "<same aaa=\"uiop\" zzz=\"qwerty\">pass</same>" );
193 if (diff.identical()) {
194 System.out.println(getName() + " - should not ideally be identical "
195 + "but JAXP implementations can reorder attributes inside NamedNodeMap");
196 }
197 assertEquals(diff.toString() + ": but should be similar",
198 true, diff.similar());
199 }
200
201 public void testDiffStringWithAttributes() throws Exception {
202 final String fruitBat = "<bat type=\"fruit\"/>",
203 longEaredBat = "<bat type=\"longeared\"/>";
204 Diff diff = buildDiff(fruitBat, longEaredBat);
205 assertEquals(diff.getClass().getName() +"\n[different] Expected "
206 + DifferenceConstants.ATTR_VALUE.getDescription()
207 + " 'fruit' but was 'longeared' - comparing "
208 + "<bat type=\"fruit\"...> at /bat[1]/@type to <bat type=\"longeared\"...> at /bat[1]/@type\n",
209 diff.toString());
210 }
211
212 public void testXMLWithDTD() throws Exception {
213 String aDTDpart = "<!DOCTYPE test ["
214 + "<!ELEMENT assertion EMPTY>"
215 + "<!ATTLIST assertion result (pass|fail) \"fail\">"
216 + "<!ELEMENT test (assertion)*>";
217 String aDTD = aDTDpart + "]>";
218 String xmlWithoutDTD = "<test>"
219 + "<assertion result=\"pass\"/>"
220 + "<assertion result=\"fail\"/>"
221 + "</test>";
222 String xmlWithDTD = aDTD + xmlWithoutDTD;
223 Diff diff = buildDiff(xmlWithDTD, xmlWithoutDTD);
224 assertTrue("similar. " + diff.toString(), diff.similar());
225 assertTrue("not identical. " + diff.toString(), !diff.identical());
226
227 File tempDtdFile = File.createTempFile(getName(), "dtd");
228 tempDtdFile.deleteOnExit();
229 FileWriter dtdWriter = new FileWriter(tempDtdFile);
230 dtdWriter.write(aDTD);
231 try {
232 String xmlWithExternalDTD = "<!DOCTYPE test SYSTEM \""
233 + tempDtdFile.toURL().toExternalForm() + "\">"
234 + xmlWithoutDTD;
235 diff = buildDiff(xmlWithDTD, xmlWithExternalDTD);
236 assertTrue("similar again. " + diff.toString(), diff.similar());
237 assertTrue("not identical again. " + diff.toString(), !diff.identical());
238 } finally {
239 tempDtdFile.delete();
240 }
241
242 String anotherDTD = aDTDpart
243 + "<!ELEMENT comment (ANY)>" + "]>";
244 String xmlWithAnotherDTD = anotherDTD + xmlWithoutDTD;
245 diff = buildDiff(xmlWithDTD, xmlWithAnotherDTD);
246 assertTrue("similar. " + diff.toString(), diff.similar());
247 assertTrue("amd identical as DTD content is not compared. " + diff.toString(), diff.identical());
248 }
249
250 /**
251 * Raised by aakture 25.04.2002
252 * Despite the name under which this defect was raised the issue is really
253 * about managing redundant whitespace
254 */
255 public void testXMLUnitDoesNotWorkWellWithFiles() throws Exception {
256 // to avoid test sequencing issues we need to restore whitespace setting
257 boolean startValueIgnoreWhitespace = XMLUnit.getIgnoreWhitespace();
258 try {
259 XMLUnit.setIgnoreWhitespace(false);
260 Diff whitespaceAwareDiff = buildDiff(test_Constants.XML_WITHOUT_WHITESPACE,
261 test_Constants.XML_WITH_WHITESPACE);
262 assertTrue(whitespaceAwareDiff.toString(),
263 !whitespaceAwareDiff.similar());
264
265 XMLUnit.setIgnoreWhitespace(true);
266 Diff whitespaceIgnoredDiff = buildDiff(test_Constants.XML_WITHOUT_WHITESPACE,
267 test_Constants.XML_WITH_WHITESPACE);
268 assertTrue(whitespaceIgnoredDiff.toString(),
269 whitespaceIgnoredDiff.similar());
270 } finally {
271 XMLUnit.setIgnoreWhitespace(startValueIgnoreWhitespace);
272 }
273 }
274
275 public void testCommentHandlingDoesntAffectWhitespaceHandling()
276 throws Exception {
277 try {
278 XMLUnit.setIgnoreComments(true);
279 testXMLUnitDoesNotWorkWellWithFiles();
280 } finally {
281 XMLUnit.setIgnoreComments(false);
282 }
283 }
284
285 public void testNormalizationDoesntAffectWhitespaceHandling()
286 throws Exception {
287 try {
288 XMLUnit.setNormalize(true);
289 testXMLUnitDoesNotWorkWellWithFiles();
290 } finally {
291 XMLUnit.setNormalize(false);
292 }
293 }
294
295 /**
296 * Raised 15.05.2002
297 */
298 public void testNamespaceIssues() throws Exception {
299 String control = "<control:abc xmlns:control=\"http://yada.com\">"
300 + "<control:xyz>text</control:xyz></control:abc>";
301 Replacement replace = new Replacement("control", "test");
302 String test = replace.replace(control);
303
304 Diff diff = buildDiff(control, test);
305 assertTrue("a-"+diff.toString(), diff.similar());
306 assertTrue("b-"+diff.toString(), !diff.identical());
307
308 Diff reverseDiff = buildDiff(test, control);
309 assertTrue("c-"+reverseDiff.toString(), reverseDiff.similar());
310 assertTrue("d-"+reverseDiff.toString(), !reverseDiff.identical());
311 }
312
313 /**
314 * Raised 16.05.2002
315 */
316 public void testDefaultNamespace() throws Exception {
317 String control = "<control:abc xmlns:control=\"http://yada.com\">"
318 + "<control:xyz>text</control:xyz></control:abc>";
319 Replacement replace = new Replacement("control:", "");
320 Replacement trim = new Replacement("xmlns:control", "xmlns");
321 String test = trim.replace(replace.replace(control));
322
323 Diff diff = buildDiff(control, test);
324 assertTrue("a-"+diff.toString(), diff.similar());
325 assertTrue("b-"+diff.toString(), !diff.identical());
326
327 Diff reverseDiff = buildDiff(test, control);
328 assertTrue("c-"+reverseDiff.toString(), reverseDiff.similar());
329 assertTrue("d-"+reverseDiff.toString(), !reverseDiff.identical());
330 }
331
332 public void testSameNameDifferentQName() throws Exception {
333 String control = "<ns1:root xmlns:ns1=\"http://example.org/ns1\" xmlns:ns2=\"http://example.org/ns2\">"
334 + "<ns1:branch>In namespace 1</ns1:branch>"
335 + "<ns2:branch>In namespace 2</ns2:branch>"
336 + "</ns1:root>";
337
338 String test = "<ns1:root xmlns:ns1=\"http://example.org/ns1\" xmlns:ns2=\"http://example.org/ns2\">"
339 + "<ns2:branch>In namespace 2</ns2:branch>"
340 + "<ns1:branch>In namespace 1</ns1:branch>"
341 + "</ns1:root>";
342
343 Diff diff = buildDiff(control, test);
344 assertTrue("a-"+diff.toString(), diff.similar());
345 assertTrue("b-"+diff.toString(), !diff.identical());
346
347 Diff reverseDiff = buildDiff(test, control);
348 assertTrue("c-"+reverseDiff.toString(), reverseDiff.similar());
349 assertTrue("d-"+reverseDiff.toString(), !reverseDiff.identical());
350 }
351
352 public void testOverrideDifferenceListener() throws Exception {
353 String control = "<vehicles><car colour=\"white\">ford fiesta</car>"
354 +"<car colour=\"red\">citroen xsara</car></vehicles>";
355 String test = "<vehicles><car colour=\"white\">nissan primera</car>"
356 +"<car colour=\"blue\">peugot 206</car></vehicles>";
357 Diff diff = buildDiff(control, test);
358 assertTrue("initially " + diff.toString(),
359 !diff.similar());
360
361 Diff diffWithIdenticalOverride = buildDiff(control, test);
362 diffWithIdenticalOverride.overrideDifferenceListener(
363 new OverrideDifferenceListener(
364 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL));
365 assertTrue("now identical"
366 + diffWithIdenticalOverride.toString(),
367 diffWithIdenticalOverride.identical());
368
369 Diff diffWithSimilarOverride = buildDiff(control, test);
370 diffWithSimilarOverride.overrideDifferenceListener(
371 new OverrideDifferenceListener(
372 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR));
373 assertTrue("no longer identical"
374 + diffWithSimilarOverride.toString(),
375 !diffWithSimilarOverride.identical());
376 assertTrue("but still similar"
377 + diffWithSimilarOverride.toString(),
378 diffWithSimilarOverride.similar());
379
380 Diff diffWithOverride = buildDiff(control, test);
381 diffWithOverride.overrideDifferenceListener(
382 new OverrideDifferenceListener(
383 DifferenceListener.RETURN_ACCEPT_DIFFERENCE));
384 assertTrue("default behaviour"
385 + diffWithOverride.toString(),
386 !diffWithOverride.similar());
387 }
388
389 public void testNamespacedAttributes() throws Exception {
390 FileReader control = new FileReader(test_Constants.BASEDIR
391 + "/tests/etc/controlNamespaces.xml");
392 FileReader test = new FileReader(test_Constants.BASEDIR
393 + "/tests/etc/testNamespaces.xml");
394 Diff diff = buildDiff(control, test);
395 diff.overrideDifferenceListener(
396 new ExpectedDifferenceListener(DifferenceConstants.NAMESPACE_PREFIX_ID));
397 assertEquals(diff.toString(), false, diff.identical());
398 assertEquals(diff.toString(), true, diff.similar());
399 }
400
401 public void testDifferentStructure() throws Exception {
402 String control = "<root><node>text</node></root>";
403 String test = "<root><node><inner-node>text</inner-node></node></root>";
404 Diff myDiff = buildDiff(control, test);
405 assertEquals(myDiff.toString(), false, myDiff.similar());
406 }
407
408 public void testRepeatedElementNamesWithAttributeQualification1() throws Exception {
409 Diff diff = buildDiff("<root><node id=\"1\"/><node id=\"2\"/></root>",
410 "<root><node id=\"2\"/><node id=\"1\"/></root>");
411 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier("id"));
412 assertFalse("should not be identical: " + diff.toString(), diff.identical());
413 assertTrue("should be similar: " + diff.toString(), diff.similar());
414 }
415
416 public void testRepeatedElementNamesWithAttributeQualification2() throws Exception {
417 Diff diff = buildDiff("<root><node id=\"1\" val=\"4\"/><node id=\"2\" val=\"3\"/></root>",
418 "<root><node id=\"2\" val=\"4\"/><node id=\"1\" val=\"3\"/></root>");
419 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier("id"));
420 assertFalse("should not be identical: " + diff.toString(), diff.identical());
421 assertFalse("should not be similar: " + diff.toString(), diff.similar());
422 }
423
424 public void testRepeatedElementNamesWithAttributeQualification3() throws Exception {
425 Diff diff = buildDiff("<root><node id=\"1\" val=\"4\"/><node id=\"2\" val=\"3\"/></root>",
426 "<root><node id=\"2\" val=\"3\"/><node id=\"1\" val=\"4\"/></root>");
427 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
428 assertFalse("should not be identical: " + diff.toString(), diff.identical());
429 assertTrue("should be similar: " + diff.toString(), diff.similar());
430 }
431
432 public void testRepeatedElementNamesWithAttributeQualification4() throws Exception {
433 Diff diff = buildDiff("<root><node id=\"1\" val=\"4\"/><node id=\"2\" val=\"3\"/></root>",
434 "<root><node id=\"2\" val=\"4\"/><node id=\"1\" val=\"3\"/></root>");
435 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
436 assertFalse("should not be identical: " + diff.toString(), diff.identical());
437 assertFalse("should not be similar: " + diff.toString(), diff.similar());
438 }
439
440 public void testRepeatedElementNamesWithNamespacedAttributeQualification() throws Exception {
441 Diff diff = buildDiff("<root xmlns:a=\"http://a.com\" xmlns:b=\"http://b.com\">"
442 + "<node id=\"1\" a:val=\"a\" b:val=\"b\"/><node id=\"2\" a:val=\"a2\" b:val=\"b2\"/></root>",
443 "<root xmlns:c=\"http://a.com\" xmlns:d=\"http://b.com\">"
444 + "<node id=\"2\" c:val=\"a2\" d:val=\"b2\"/><node id=\"1\" c:val=\"a\" d:val=\"b\"/></root>");
445 diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
446 diff.overrideDifferenceListener(new ExpectedDifferenceListener(
447 new int[] {DifferenceConstants.NAMESPACE_PREFIX_ID, DifferenceConstants.CHILD_NODELIST_SEQUENCE_ID}));
448 assertFalse("should not be identical: " + diff.toString(), diff.identical());
449 assertTrue("should be similar: " + diff.toString(), diff.similar());
450 }
451
452 public void testRepeatedElementNamesWithTextQualification() throws Exception {
453 Diff diff = buildDiff("<root><node>1</node><node>2</node></root>",
454 "<root><node>2</node><node>1</node></root>");
455 diff.overrideElementQualifier(new ElementNameAndTextQualifier());
456 diff.overrideDifferenceListener(
457 new ExaminingExpectedDifferenceListener(DifferenceConstants.CHILD_NODELIST_SEQUENCE_ID) {
458 private int i=0;
459 protected void examineDifferenceContents(Difference difference) {
460 ++i;
461 assertEquals("/root[1]/node[" + i +"]",
462 difference.getControlNodeDetail().getXpathLocation());
463 }
464 });
465 assertFalse("should not be identical: " + diff.toString(), diff.identical());
466 assertTrue("should be similar: " + diff.toString(), diff.similar());
467 }
468
469 // defect raised by Kevin Krouse Jan 2003
470 public void testXMLNSNumberOfAttributes() throws Exception {
471 Diff diff = buildDiff("<root xmlns=\"qwerty\"><node/></root>",
472 "<root xmlns=\"qwerty\" xmlns:qwerty=\"qwerty\"><qwerty:node/></root>");
473 assertTrue(diff.toString(), diff.similar());
474 assertFalse(diff.toString(), diff.identical());
475 }
476
477 protected Diff buildDiff(Document control, Document test) {
478 return new Diff(control, test);
479 }
480
481 protected Diff buildDiff(String control, String test) throws Exception {
482 return new Diff(control, test);
483 }
484
485 protected Diff buildDiff(Reader control, Reader test) throws Exception {
486 return new Diff(control, test);
487 }
488
489 protected Diff buildDiff(String control, String test,
490 DifferenceEngine engine) throws Exception {
491 return new Diff(XMLUnit.buildControlDocument(control),
492 XMLUnit.buildTestDocument(test), engine);
493 }
494
495 /**
496 * Construct a test
497 * @param name Test name
498 */
499 public test_Diff(String name){
500 super(name);
501 }
502
503 private class OverrideDifferenceListener implements DifferenceListener {
504 private final int overrideValue;
505 private OverrideDifferenceListener(int overrideValue) {
506 this.overrideValue = overrideValue;
507 }
508 public int differenceFound(Difference difference) {
509 return overrideValue;
510 }
511 public void skippedComparison(Node control, Node test) {
512 }
513 }
514
515 private class ExpectedDifferenceListener implements DifferenceListener {
516 private final Set expectedIds;
517 private ExpectedDifferenceListener(int expectedIdValue) {
518 this(new int[] {expectedIdValue});
519 }
520 private ExpectedDifferenceListener(int[] expectedIdValues) {
521 this.expectedIds = new HashSet(expectedIdValues.length);
522 for (int i=0; i < expectedIdValues.length; ++i) {
523 expectedIds.add(new Integer(expectedIdValues[i]));
524 }
525 }
526 public int differenceFound(Difference difference) {
527 assertTrue(difference.toString(), expectedIds.contains(new Integer(difference.getId())));
528 examineDifferenceContents(difference);
529 return RETURN_ACCEPT_DIFFERENCE;
530 }
531 public void skippedComparison(Node control, Node test) {
532 }
533 protected void examineDifferenceContents(Difference difference) {
534 }
535 }
536
537 private abstract class ExaminingExpectedDifferenceListener extends ExpectedDifferenceListener {
538 private ExaminingExpectedDifferenceListener(int expectedIdValue) {
539 super(expectedIdValue);
540 }
541 protected abstract void examineDifferenceContents(Difference difference) ;
542 }
543
544
545 public void testIssue1189681() throws Exception {
546 String left = "" +
547 "<farm>\n" +
548 "<size>100</size>\n" +
549 " <animal>\n" +
550 "<name>Cow</name>\n" +
551 " </animal>\n"
552 +
553 " <animal>\n" +
554 "<name>Sheep</name>\n" +
555 " </animal>\n"
556 +
557 "</farm>";
558 String right = "" +
559 "<farm>\n" +
560 " <animal>\n" +
561 "<name>Sheep</name>\n" +
562 " </animal>\n"
563 +
564 " <size>100</size>\n" +
565 " <animal>\n" +
566 " <name>Cow</name>\n" +
567 " </animal>\n" +
568 "</farm>";
569 assertFalse(buildDiff(left, right).similar());
570 }
571
572 public void testCDATANoIgnore() throws Exception {
573 String expected = "<a>Hello</a>";
574 String actual = "<a><![CDATA[Hello]]></a>";
575 assertFalse(buildDiff(expected, actual).similar());
576 assertFalse(buildDiff(expected, actual).identical());
577 }
578
579 public void testCDATAIgnore() throws Exception {
580 try {
581 XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
582 String expected = "<a>Hello</a>";
583 String actual = "<a><![CDATA[Hello]]></a>";
584 assertTrue(buildDiff(expected, actual).similar());
585 assertTrue(buildDiff(expected, actual).identical());
586 } finally {
587 XMLUnit.setIgnoreDiffBetweenTextAndCDATA(false);
588 }
589 }
590
591 public void testCommentHandling() throws Exception {
592 String xml1 = "<foo><!-- test --><bar a=\"b\"/> </foo>";
593 String xml2 = "<foo><bar a=\"b\"><!-- test --></bar> </foo>";
594 try {
595 assertFalse(buildDiff(xml1, xml2).identical());
596 assertFalse(buildDiff(xml1, xml2).similar());
597 XMLUnit.setIgnoreComments(true);
598 assertTrue(buildDiff(xml1, xml2).identical());
599 assertTrue(buildDiff(xml1, xml2).similar());
600 } finally {
601 XMLUnit.setIgnoreComments(false);
602 }
603 }
604
605 public void testWhitespaceHandlingDoesntAffectCommentHandling()
606 throws Exception {
607 try {
608 XMLUnit.setIgnoreWhitespace(true);
609 testCommentHandling();
610 } finally {
611 XMLUnit.setIgnoreWhitespace(false);
612 }
613 }
614
615 public void testNormalizationDoesntAffectCommentHandling()
616 throws Exception {
617 try {
618 XMLUnit.setNormalize(true);
619 testCommentHandling();
620 } finally {
621 XMLUnit.setNormalize(false);
622 }
623 }
624
625 public void testNormalization() throws Exception {
626 Document control = XMLUnit.newControlParser().newDocument();
627 Element root = control.createElement("root");
628 control.appendChild(root);
629 root.appendChild(control.createTextNode("Text 1"));
630 root.appendChild(control.createTextNode(" and 2"));
631 Element inner = control.createElement("inner");
632 root.appendChild(inner);
633 inner.appendChild(control.createTextNode("Text 3 and 4"));
634
635 Document test = XMLUnit.newTestParser().newDocument();
636 root = test.createElement("root");
637 test.appendChild(root);
638 root.appendChild(test.createTextNode("Text 1 and 2"));
639 inner = test.createElement("inner");
640 root.appendChild(inner);
641 inner.appendChild(test.createTextNode("Text 3"));
642 inner.appendChild(test.createTextNode(" and 4"));
643
644 assertFalse(buildDiff(control, test).identical());
645 try {
646 XMLUnit.setNormalize(true);
647 assertTrue(buildDiff(control, test).identical());
648 assertTrue(buildDiff(control, test).similar());
649 } finally {
650 XMLUnit.setNormalize(false);
651 }
652 assertFalse(buildDiff(control, test).similar());
653 }
654
655 // fails with Java 5 and later
656 public void XtestWhitespaceHandlingDoesntAffectNormalization()
657 throws Exception {
658 try {
659 XMLUnit.setIgnoreWhitespace(true);
660 testNormalization();
661 } finally {
662 XMLUnit.setIgnoreWhitespace(false);
663 }
664 }
665
666 // fails with Java 5 and later
667 public void XtestCommentHandlingDoesntAffectNormalization()
668 throws Exception {
669 try {
670 XMLUnit.setIgnoreComments(true);
671 testNormalization();
672 } finally {
673 XMLUnit.setIgnoreComments(false);
674 }
675 }
676
677 public void testNormalizedWhitespace() throws Exception {
678 String xml1 = "<foo>a = b;</foo>";
679 String xml2 = "<foo>\r\n\ta =\tb; \r\n</foo>";
680 try {
681 assertFalse(buildDiff(xml1, xml2).identical());
682 assertFalse(buildDiff(xml1, xml2).similar());
683 XMLUnit.setNormalizeWhitespace(true);
684 assertTrue(buildDiff(xml1, xml2).identical());
685 assertTrue(buildDiff(xml1, xml2).similar());
686 } finally {
687 XMLUnit.setNormalizeWhitespace(false);
688 }
689 }
690
691 /**
692 * inspired by {@link
693 * http://day-to-day-stuff.blogspot.com/2007/05/comparing-xml-in-junit-test.html
694 * Erik von Oosten's Weblog}, made us implement special handling
695 * of schemaLocation.
696 */
697 public void testNamespacePrefixDiff() throws Exception {
698 String xml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
699 + "<Message xmlns=\"http://www.a.nl/a10.xsd\""
700 + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
701 + " xsi:schemaLocation=\"C:/longpath/a10.xsd\""
702 + ">"
703 + "<MessageHeader/>"
704 + "</Message>";
705 String xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
706 + "<a:Message xmlns:a=\"http://www.a.nl/a10.xsd\">"
707 + "<a:MessageHeader/>"
708 + "</a:Message>";
709 Diff d = buildDiff(xml1, xml2);
710 assertFalse(d.toString(), d.identical());
711 assertTrue(d.toString(), d.similar());
712 }
713
714 /**
715 * Bug Report 1779701
716 * @see http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1779701&amp;group_id=23187&amp;atid=377768
717 */
718 public void testWhitespaceAndNamespaces() throws Exception {
719 String control =
720 "<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>"
721 + "\r\n <env:Header/>"
722 + "\r\n </env:Envelope>";
723 String test =
724 "<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>"
725 + "<env:Header/>"
726 + "</env:Envelope>";
727 XMLUnit.setIgnoreWhitespace(true);
728 try {
729 Diff diff = buildDiff(control, test);
730 assertTrue(diff.toString(), diff.identical());
731 } finally {
732 XMLUnit.setIgnoreWhitespace(false);
733 }
734 }
735
736 /**
737 * Bug Report 1863632
738 * @see http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1863632&amp;group_id=23187&amp;atid=377768
739 */
740 public void testBasicWhitespaceHandling() throws Exception {
741 String control = "<a><b/></a>";
742 String test = "<a>\r\n <b/>\r\n</a>";
743 XMLUnit.setIgnoreWhitespace(true);
744 try {
745 Diff diff = buildDiff(control, test);
746 assertTrue(diff.toString(), diff.identical());
747 } finally {
748 XMLUnit.setIgnoreWhitespace(false);
749 }
750 }
751
752 public void testUpgradingOfRecoverableDifference() throws Exception {
753 String control = "<foo:bar xmlns:foo='urn:foo'/>";
754 String test = "<bar xmlns='urn:foo'/>";
755 Diff diff = buildDiff(control, test);
756 assertFalse(diff.toString(), diff.identical());
757 assertTrue(diff.toString(), diff.similar());
758
759 diff = buildDiff(control, test);
760 diff.overrideDifferenceListener(new DifferenceListener() {
761 public int differenceFound(Difference d) {
762 return RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT;
763 }
764 public void skippedComparison(Node c, Node t) {
765 fail("skippedComparison shouldn't get invoked");
766 }
767 });
768
769 assertFalse(diff.toString(), diff.identical());
770 assertFalse(diff.toString(), diff.similar());
771 }
772
773 public void testMatchTrackerSetViaOverride() throws Exception {
774 Diff diff = buildDiff("<foo/>", "<foo/>");
775 final int[] count = new int[1];
776 diff.overrideMatchTracker(new MatchTracker() {
777 public void matchFound(Difference d) {
778 count[0]++;
779 }
780 });
781 assertTrue(diff.identical());
782 // NODE_TYPE (not null), NODE_TYPE(Document), NAMESPACE_URI(none),
783 // NAMESPACE_PREFIX(none), HAS_DOCTYPE_DECLARATION(no),
784 // HAS_CHILD_NODES(true)
785 //
786 // NODE_TYPE(Element), NAMESPACE_URI(none),
787 // NAMESPACE_PREFIX(none), ELEMENT_TAG_NAME(foo),
788 // ELEMENT_NUM_ATTRIBUTE(none), HAS_CHILD_NODES(false),
789 // CHILD_NODELIST_LENGTH(0)
790 assertEquals(13, count[0]);
791 }
792
793 public void testMatchTrackerSetViaEngine() throws Exception {
794 final int[] count = new int[1];
795 DifferenceEngine engine =
796 new DifferenceEngine(new ComparisonController() {
797 public boolean haltComparison(Difference afterDifference) {
798 fail("haltComparison invoked");
799 // NOTREACHED
800 return false;
801 }
802 }, new MatchTracker() {
803 public void matchFound(Difference d) {
804 count[0]++;
805 }
806 });
807 Diff diff = buildDiff("<foo/>", "<foo/>", engine);
808 assertTrue(diff.identical());
809 // NODE_TYPE (not null), NODE_TYPE(Document), NAMESPACE_URI(none),
810 // NAMESPACE_PREFIX(none), HAS_DOCTYPE_DECLARATION(no),
811 // HAS_CHILD_NODES(true)
812 //
813 // NODE_TYPE(Element), NAMESPACE_URI(none),
814 // NAMESPACE_PREFIX(none), ELEMENT_TAG_NAME(foo),
815 // ELEMENT_NUM_ATTRIBUTE(none), HAS_CHILD_NODES(false),
816 // CHILD_NODELIST_LENGTH(0)
817 assertEquals(13, count[0]);
818 }
819
820 public void testMatchTrackerSetViaOverrideOnEngine() throws Exception {
821 DifferenceEngine engine =
822 new DifferenceEngine(new ComparisonController() {
823 public boolean haltComparison(Difference afterDifference) {
824 fail("haltComparison invoked");
825 // NOTREACHED
826 return false;
827 }
828 });
829 Diff diff = buildDiff("<foo/>", "<foo/>", engine);
830 final int[] count = new int[1];
831 diff.overrideMatchTracker(new MatchTracker() {
832 public void matchFound(Difference d) {
833 count[0]++;
834 }
835 });
836 assertTrue(diff.identical());
837 // NODE_TYPE (not null), NODE_TYPE(Document), NAMESPACE_URI(none),
838 // NAMESPACE_PREFIX(none), HAS_DOCTYPE_DECLARATION(no),
839 // HAS_CHILD_NODES(true)
840 //
841 // NODE_TYPE(Element), NAMESPACE_URI(none),
842 // NAMESPACE_PREFIX(none), ELEMENT_TAG_NAME(foo),
843 // ELEMENT_NUM_ATTRIBUTE(none), HAS_CHILD_NODES(false)
844 // CHILD_NODELIST_LENGTH(0)
845 assertEquals(13, count[0]);
846 }
847
848 public void testCDATAAndIgnoreWhitespace() throws Exception {
849 String control = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
850 + "<Data><Person><Name><![CDATA[JOE]]></Name></Person></Data>";
851
852 String test = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
853 +"<Data>"
854 +" <Person>"
855 +" <Name>"
856 +" <![CDATA[JOE]]>"
857 +" </Name>"
858 +" </Person>"
859 +"</Data>";
860
861 XMLUnit.setIgnoreWhitespace(true);
862 XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
863 try {
864 Diff diff = buildDiff(control, test);
865 assertTrue(diff.toString(), diff.similar());
866 } finally {
867 XMLUnit.setIgnoreWhitespace(false);
868 XMLUnit.setIgnoreDiffBetweenTextAndCDATA(false);
869 }
870 }
871
872 /**
873 * Not a real test. Need something that actually fails unless I
874 * set the flag.
875 */
876 public void testEntityExpansion() throws Exception {
877 String control = "<root>bla&#13;bla</root>";
878 String test = "<root>bla&#xD;bla</root>";
879 //XMLUnit.setExpandEntityReferences(true);
880 try {
881 Diff diff = buildDiff(control, test);
882 assertTrue(diff.toString(), diff.similar());
883 } finally {
884 XMLUnit.setExpandEntityReferences(false);
885 }
886 }
887
888 /**
889 * @see https://sourceforge.net/tracker/?func=detail&aid=2807167&group_id=23187&atid=377768
890 */
891 public void testIssue2807167() throws Exception {
892 String test = "<tag>" +
893 "<child amount=\"100\" />" +
894 "<child amount=\"100\" />" +
895 "<child amount=\"100\" />" +
896 "<child amount=\"250\" />" +
897 "<child amount=\"100\" />" +
898 "</tag>";
899
900 String control = "<tag>" +
901 "<child amount=\"100\" />" +
902 "<child amount=\"100\" />" +
903 "<child amount=\"250\" />" +
904 "<child amount=\"100\" />" +
905 "<child amount=\"100\" />" +
906 "</tag>";
907
908 Diff diff = new Diff(control, test);
909 diff.overrideElementQualifier(new
910 ElementNameAndAttributeQualifier());
911 assertTrue(diff.toString(), diff.similar());
912 }
913
914 /**
915 * @see http://sourceforge.net/tracker/?func=detail&atid=377768&aid=3602981&group_id=23187
916 */
917 public void testXsiTypeSpecialCase() throws Exception {
918 String test = "<ns1:Square xsi:type=\"ns1:Shape\" "
919 + "xmlns:ns1=\"http://example.com/\" "
920 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
921
922 String control = "<ns2:Square xsi:type=\"ns2:Shape\" "
923 + "xmlns:ns2=\"http://example.com/\" "
924 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
925 Diff diff = new Diff(control, test);
926 assertTrue(diff.toString(), diff.similar());
927 }
928
929 public void testXsiTypeSpecialCaseShortLocalName() throws Exception {
930 String test = "<ns1:Square xsi:type=\"ns1:a\" "
931 + "xmlns:ns1=\"http://example.com/\" "
932 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
933
934 String control = "<ns2:Square xsi:type=\"ns2:a\" "
935 + "xmlns:ns2=\"http://example.com/\" "
936 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
937 Diff diff = new Diff(control, test);
938 assertTrue(diff.toString(), diff.similar());
939 }
940
941 public void testXsiTypeSpecialCaseWorksWithDefaultNs() throws Exception {
942 String test = "<Square xsi:type=\"Shape\" "
943 + "xmlns=\"http://example.com/\" "
944 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
945
946 String control = "<ns2:Square xsi:type=\"ns2:Shape\" "
947 + "xmlns:ns2=\"http://example.com/\" "
948 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
949 Diff diff = new Diff(control, test);
950 assertTrue(diff.toString(), diff.similar());
951 }
952
953 public void testXsiTypeSpecialCaseInheritsParentNs() throws Exception {
954 String test = "<ns1:Shapes xmlns:ns1=\"http://example.com/\">"
955 + "<ns1:Square xsi:type=\"ns1:Shape\" "
956 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>"
957 + "</ns1:Shapes>";
958
959 String control = "<ns2:Shapes xmlns:ns2=\"http://example.com/\">"
960 + "<ns2:Square xsi:type=\"ns2:Shape\" "
961 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>"
962 + "</ns2:Shapes>";
963 Diff diff = new Diff(control, test);
964 assertTrue(diff.toString(), diff.similar());
965 }
966
967 public void testXsiTypeSpecialCaseDoesntIgnorePrefix() throws Exception {
968 String test = "<ns1:Square xsi:type=\"ns1:Shape\" "
969 + "xmlns:ns1=\"http://example.com/\" "
970 + "xmlns:ns2=\"http://example.com/another-uri/\" "
971 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
972
973 String control = "<ns1:Square xsi:type=\"ns2:Shape\" "
974 + "xmlns:ns1=\"http://example.com/\" "
975 + "xmlns:ns2=\"http://example.com/another-uri/\" "
976 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
977 Diff diff = new Diff(control, test);
978 assertFalse(diff.toString(), diff.similar());
979 }
980 public void testXsiNil() throws Exception {
981 String test = "<foo xsi:nil=\"true\" "
982 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
983
984 String control = "<foo xsi:nil=\"false\" "
985 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>";
986 Diff diff = new Diff(control, test);
987 assertFalse(diff.toString(), diff.similar());
988 }
989 }
990
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2009,2014, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.List;
39 import junit.framework.TestCase;
40
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Node;
43
44 /**
45 * @author TimBacon
46 */
47 public class test_Difference extends TestCase {
48 private final Difference ORIGINAL =
49 DifferenceConstants.ATTR_NAME_NOT_FOUND;
50
51 public void testCopyConstructor() {
52 Difference copy = new Difference(ORIGINAL, null, null);
53 assertEquals("id", ORIGINAL.getId(), copy.getId());
54 assertEquals("description",
55 ORIGINAL.getDescription(), copy.getDescription());
56 assertEquals("recoverable",
57 ORIGINAL.isRecoverable(), copy.isRecoverable());
58
59 assertEquals("precondition", false, ORIGINAL.isRecoverable());
60 copy.setRecoverable(true);
61 assertEquals("recoverable again",
62 !ORIGINAL.isRecoverable(), copy.isRecoverable());
63 }
64
65 public void testEquals() {
66 assertTrue("not equal to null", !ORIGINAL.equals(null));
67 assertTrue("not equal to other class", !ORIGINAL.equals("aString"));
68 assertEquals("equal to self", ORIGINAL, ORIGINAL);
69
70 Difference copy = new Difference(ORIGINAL, null, null);
71 assertEquals("equal to copy", ORIGINAL, copy);
72 }
73
74 public void testToString() throws Exception {
75 String originalAsString = "Difference (#" + ORIGINAL.getId()
76 + ") " + ORIGINAL.getDescription();
77 assertEquals("Original", originalAsString, ORIGINAL.toString());
78
79 Document document = XMLUnit.newControlParser().newDocument();
80
81 Node controlNode = document.createComment("control");
82 NodeDetail controlNodeDetail = new NodeDetail(controlNode.getNodeValue(),
83 controlNode, "/testToString/comment()");
84
85 Node testNode = document.createComment("test");
86 NodeDetail testNodeDetail = new NodeDetail(testNode.getNodeValue(),
87 testNode, "/testToString/comment()");
88
89 Difference difference = new Difference(DifferenceConstants.COMMENT_VALUE,
90 controlNodeDetail, testNodeDetail);
91 StringBuffer buf = new StringBuffer("Expected ")
92 .append(DifferenceConstants.COMMENT_VALUE.getDescription())
93 .append(" 'control' but was 'test' - comparing ");
94 NodeDescriptor.appendNodeDetail(buf, controlNodeDetail);
95 buf.append(" to ");
96 NodeDescriptor.appendNodeDetail(buf, testNodeDetail);
97 assertEquals("detail", buf.toString(), difference.toString());
98 }
99
100 // bug 2386807
101 public void testXpathOfMissingAttribute() throws Exception {
102 Diff d = new Diff("<foo><bar a=\"x\" y=\"z\"/></foo>",
103 "<foo><bar a=\"x\"/></foo>");
104 DetailedDiff dd = new DetailedDiff(d);
105 List diffs = dd.getAllDifferences();
106 assertEquals(2, diffs.size());
107 Difference d1 = (Difference) diffs.get(0);
108 assertEquals(DifferenceConstants.ELEMENT_NUM_ATTRIBUTES_ID,
109 d1.getId());
110 assertEquals("/foo[1]/bar[1]",
111 d1.getControlNodeDetail().getXpathLocation());
112 assertEquals("/foo[1]/bar[1]",
113 d1.getTestNodeDetail().getXpathLocation());
114 Difference d2 = (Difference) diffs.get(1);
115 assertEquals(DifferenceConstants.ATTR_NAME_NOT_FOUND_ID,
116 d2.getId());
117 assertEquals("/foo[1]/bar[1]/@y",
118 d2.getControlNodeDetail().getXpathLocation());
119 assertEquals("/foo[1]/bar[1]",
120 d2.getTestNodeDetail().getXpathLocation());
121 }
122
123 public void testXpathOfMissingTestAttribute() throws Exception {
124 Diff d = new Diff("<foo><bar a=\"x\"/></foo>",
125 "<foo><bar a=\"x\" y=\"z\"/></foo>");
126 DetailedDiff dd = new DetailedDiff(d);
127 List diffs = dd.getAllDifferences();
128 assertEquals(2, diffs.size());
129 Difference d1 = (Difference) diffs.get(0);
130 assertEquals(DifferenceConstants.ELEMENT_NUM_ATTRIBUTES_ID,
131 d1.getId());
132 assertEquals("/foo[1]/bar[1]",
133 d1.getControlNodeDetail().getXpathLocation());
134 assertEquals("/foo[1]/bar[1]",
135 d1.getTestNodeDetail().getXpathLocation());
136 Difference d2 = (Difference) diffs.get(1);
137 assertEquals(DifferenceConstants.ATTR_NAME_NOT_FOUND_ID,
138 d2.getId());
139 assertEquals("/foo[1]/bar[1]",
140 d2.getControlNodeDetail().getXpathLocation());
141 assertEquals("/foo[1]/bar[1]/@y",
142 d2.getTestNodeDetail().getXpathLocation());
143 }
144
145 /**
146 * Constructor for test_Difference.
147 * @param name
148 */
149 public test_Difference(String name) {
150 super(name);
151 }
152
153 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008,2013-2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileWriter;
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.Iterator;
43
44 import javax.xml.parsers.DocumentBuilder;
45 import junit.framework.TestCase;
46 import junit.framework.TestSuite;
47
48 import org.w3c.dom.Attr;
49 import org.w3c.dom.CDATASection;
50 import org.w3c.dom.Comment;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.DocumentType;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.NamedNodeMap;
55 import org.w3c.dom.Node;
56 import org.w3c.dom.ProcessingInstruction;
57 import org.w3c.dom.Text;
58 import org.xml.sax.SAXException;
59
60 /**
61 * JUnit test for DifferenceEngine
62 */
63 public class test_DifferenceEngine extends TestCase implements DifferenceConstants {
64 private CollectingDifferenceListener listener;
65 private DifferenceEngine engine;
66 private Document document;
67
68 private final ComparisonController PSEUDO_DIFF = new SimpleComparisonController();
69 private final ComparisonController PSEUDO_DETAILED_DIFF = new NeverHaltingComparisonController();
70
71 private final static ElementQualifier
72 DEFAULT_ELEMENT_QUALIFIER = new ElementNameQualifier();
73 private final static String TEXT_A = "the pack on my back is aching";
74 private final static String TEXT_B = "the straps seem to cut me like a knife";
75 private final static String COMMENT_A = "Im no clown I wont back down";
76 private final static String COMMENT_B = "dont need you to tell me whats going down";
77 private final static String[] PROC_A = {"down", "down down"};
78 private final static String[] PROC_B = {"dadada", "down"};
79 private final static String CDATA_A = "I'm standing alone, you're weighing the gold";
80 private final static String CDATA_B = "I'm watching you sinking... Fools Gold";
81 private final static String ATTR_A = "These boots were made for walking";
82 private final static String ATTR_B = "The marquis de sade never wore no boots like these";
83
84 private void assertDifferentText(Text control, Text test,
85 Difference difference) {
86 try {
87 engine.compareText(control, test, listener);
88 } catch (DifferenceEngine.DifferenceFoundException e) {
89 }
90 assertEquals(difference.getId(), listener.comparingWhat);
91 assertEquals(true, listener.different);
92 resetListener();
93 }
94
95 public void testCompareText() throws Exception {
96 String expected = TEXT_A;
97 String actual = TEXT_B;
98 Text control = document.createTextNode(expected);
99 Text test = document.createTextNode(actual);
100
101 assertDifferentText(control, test, TEXT_VALUE);
102 }
103
104 private void assertDifferentProcessingInstructions (
105 ProcessingInstruction control, ProcessingInstruction test,
106 Difference difference) {
107 try {
108 engine.compareProcessingInstruction(control, test, listener);
109 } catch (DifferenceEngine.DifferenceFoundException e) {
110 }
111 assertEquals(difference.getId(), listener.comparingWhat);
112 assertEquals(true, listener.different);
113 resetListener();
114 }
115
116 public void testCompareProcessingInstruction() throws Exception {
117 String[] expected = PROC_A;
118 String[] actual = PROC_B;
119 ProcessingInstruction control = document.createProcessingInstruction(
120 expected[0], expected[1]);
121 ProcessingInstruction test = document.createProcessingInstruction(
122 actual[0], actual[1]);
123
124 assertDifferentProcessingInstructions(control, test,
125 PROCESSING_INSTRUCTION_TARGET);
126
127 ProcessingInstruction control2 = document.createProcessingInstruction(
128 expected[0], expected[1]);
129 ProcessingInstruction test2 = document.createProcessingInstruction(
130 expected[0], actual[1]);
131 assertDifferentProcessingInstructions(control2, test2,
132 PROCESSING_INSTRUCTION_DATA);
133 }
134
135 private void assertDifferentComments(Comment control, Comment test,
136 Difference difference) {
137 try {
138 engine.compareComment(control, test, listener);
139 } catch (DifferenceEngine.DifferenceFoundException e) {
140 }
141 assertEquals(difference.getId(), listener.comparingWhat);
142 assertEquals(true, listener.different);
143 resetListener();
144 }
145
146 public void testCompareComment() throws Exception {
147 String expected = COMMENT_A;
148 String actual = COMMENT_B;
149 Comment control = document.createComment(expected);
150 Comment test = document.createComment(actual);
151
152 assertDifferentComments(control, test, COMMENT_VALUE);
153 }
154
155 private void assertDifferentCDATA(CDATASection control, CDATASection test,
156 Difference difference) {
157 try {
158 engine.compareCDataSection(control, test, listener);
159 } catch (DifferenceEngine.DifferenceFoundException e) {
160 }
161 assertEquals(difference.getId(), listener.comparingWhat);
162 assertEquals(true, listener.different);
163 resetListener();
164 }
165
166 public void testCompareCDATA() throws Exception {
167 String expected = CDATA_A ;
168 String actual = CDATA_B ;
169 CDATASection control = document.createCDATASection(expected);
170 CDATASection test = document.createCDATASection(actual);
171
172 assertDifferentCDATA(control, test, CDATA_VALUE);
173 }
174
175 private void assertDifferentDocumentTypes(DocumentType control,
176 DocumentType test, Difference difference, boolean fatal) {
177 try {
178 engine.compareDocumentType(control, test, listener);
179 if (fatal) {
180 fail("Expected fatal difference!");
181 }
182 } catch (DifferenceEngine.DifferenceFoundException e) {
183 if (!fatal) {
184 fail("Expected similarity not fatal difference!");
185 }
186 }
187 assertEquals(difference.getId(), listener.comparingWhat);
188 assertEquals(fatal, listener.different);
189 resetListener();
190 }
191
192 public void testCompareDocumentType() throws Exception {
193 File tmpFile = File.createTempFile("Roses","dtd");
194 tmpFile.deleteOnExit();
195 String tmpDTD = "<!ELEMENT leaf (#PCDATA)><!ELEMENT root (leaf)>";
196 new FileWriter(tmpFile).write(tmpDTD);
197 String rosesDTD = tmpFile.toURL().toExternalForm();
198
199 File altTmpFile = File.createTempFile("TheCrows", "dtd");
200 altTmpFile.deleteOnExit();
201 new FileWriter(altTmpFile).write(tmpDTD);
202 String theCrowsDTD = altTmpFile.toURL().toExternalForm();
203
204 Document controlDoc = XMLUnit.buildControlDocument(
205 "<!DOCTYPE root PUBLIC 'Stone' '" + rosesDTD + "'>"
206 + "<root><leaf/></root>");
207 Document testDoc = XMLUnit.buildTestDocument(
208 "<!DOCTYPE tree PUBLIC 'Stone' '" + rosesDTD + "'>"
209 + "<tree><leaf/></tree>");
210
211 DocumentType control = controlDoc.getDoctype();
212 DocumentType test = testDoc.getDoctype();
213
214 assertDifferentDocumentTypes(control, test, DOCTYPE_NAME, true);
215
216 test = XMLUnit.buildTestDocument("<!DOCTYPE root PUBLIC 'id' '" + rosesDTD + "'>"
217 + "<root><leaf/></root>").getDoctype();
218 assertDifferentDocumentTypes(control, test, DOCTYPE_PUBLIC_ID, true);
219
220 test = XMLUnit.buildTestDocument("<!DOCTYPE root SYSTEM '" + rosesDTD + "'>"
221 + "<root><leaf/></root>").getDoctype();
222 assertDifferentDocumentTypes(control, test, DOCTYPE_PUBLIC_ID, true);
223
224 test = XMLUnit.buildTestDocument("<!DOCTYPE root PUBLIC 'Stone' '" + theCrowsDTD + "'>"
225 + "<root><leaf/></root>").getDoctype();
226 assertDifferentDocumentTypes(control, test, DOCTYPE_SYSTEM_ID, false);
227
228 test = XMLUnit.buildTestDocument("<!DOCTYPE root SYSTEM '" + theCrowsDTD + "'>"
229 + "<root><leaf/></root>").getDoctype();
230 assertDifferentDocumentTypes(control, test, DOCTYPE_PUBLIC_ID, true);
231
232 control = XMLUnit.buildTestDocument("<!DOCTYPE root SYSTEM '" + rosesDTD + "'>"
233 + "<root><leaf/></root>").getDoctype();
234 assertDifferentDocumentTypes(control, test, DOCTYPE_SYSTEM_ID, false);
235 }
236
237 private void assertDifferentAttributes(Attr control, Attr test,
238 Difference difference, boolean fatal) {
239 try {
240 engine.compareAttribute(control, test, listener);
241 if (fatal) {
242 fail("Expecting fatal difference!");
243 }
244 } catch (DifferenceEngine.DifferenceFoundException e) {
245 if (!fatal) {
246 fail("Expecting similarity not fatal difference!");
247 }
248 }
249 assertEquals(difference.getId(), listener.comparingWhat);
250 assertEquals(fatal, listener.different);
251 resetListener();
252 }
253
254 public void testCompareAttribute() throws Exception {
255 String expected = ATTR_A;
256 String actual = ATTR_B;
257 Attr control = document.createAttribute(getName());
258 control.setValue(expected);
259 Attr test = document.createAttribute(getName());
260 test.setValue(actual);
261
262 assertDifferentAttributes(control, test, ATTR_VALUE, true);
263
264 String doctypeDeclaration = "<!DOCTYPE manchester [" +
265 "<!ELEMENT sound EMPTY><!ATTLIST sound sorted (true|false) \"true\">" +
266 "<!ELEMENT manchester (sound)>]>";
267 Document controlDoc = XMLUnit.buildControlDocument(doctypeDeclaration +
268 "<manchester><sound sorted=\"true\"/></manchester>");
269 control = (Attr) controlDoc.getDocumentElement().getFirstChild()
270 .getAttributes().getNamedItem("sorted");
271
272 Document testDoc = XMLUnit.buildTestDocument(doctypeDeclaration +
273 "<manchester><sound/></manchester>");
274 test = (Attr) testDoc.getDocumentElement().getFirstChild()
275 .getAttributes().getNamedItem("sorted");
276
277 assertDifferentAttributes(control, test,
278 ATTR_VALUE_EXPLICITLY_SPECIFIED, false);
279 }
280
281 private void assertDifferentElements(Element control, Element test,
282 Difference difference) {
283 try {
284 engine.compareElement(control, test, listener);
285 } catch (DifferenceEngine.DifferenceFoundException e) {
286 }
287 assertEquals(difference.getId(), listener.comparingWhat);
288 assertEquals(true, listener.different);
289 resetListener();
290 }
291
292 public void testCompareElements() throws Exception {
293 Document document = XMLUnit.buildControlDocument(
294 "<down><im standing=\"alone\"/><im watching=\"you\" all=\"\"/>"
295 + "<im watching=\"you all\"/><im watching=\"you sinking\"/></down>");
296 Element control = (Element) document.getDocumentElement();
297 Element test = (Element) control.getFirstChild();
298
299 assertDifferentElements(control, test, ELEMENT_TAG_NAME);
300
301 // compare im#1 to im#2
302 control = test;
303 test = (Element) control.getNextSibling();
304 assertDifferentElements(control, test, ELEMENT_NUM_ATTRIBUTES);
305
306 // compare im#1 to im#3
307 test = (Element) test.getNextSibling();
308 assertDifferentElements(control, test, ATTR_NAME_NOT_FOUND);
309
310 // compare im#3 to im#4
311 control = test;
312 test = (Element) control.getNextSibling();
313 assertDifferentElements(control, test, ATTR_VALUE);
314 }
315
316 public void testCompareNode() throws Exception {
317 Document controlDocument = XMLUnit.buildControlDocument("<root>"
318 + "<!-- " + COMMENT_A + " -->"
319 + "<?" + PROC_A[0] + " "+ PROC_A[1] + " ?>"
320 + "<elem attr=\"" + ATTR_A + "\">" + TEXT_A + "</elem></root>");
321 Document testDocument = XMLUnit.buildTestDocument("<root>"
322 + "<!-- " + COMMENT_B + " -->"
323 + "<?" + PROC_B[0] + " "+ PROC_B[1] + " ?>"
324 + "<elem attr=\"" + ATTR_B + "\">" + TEXT_B + "</elem></root>");
325
326 engine.compare(controlDocument, testDocument, listener, null);
327
328 Node control = controlDocument.getDocumentElement().getFirstChild();
329 Node test = testDocument.getDocumentElement().getFirstChild();
330
331 do {
332 resetListener();
333 engine.compare(control, test, listener, null);
334 assertEquals(true, -1 != listener.comparingWhat);
335 assertEquals(false, listener.nodesSkipped);
336
337 resetListener();
338 engine.compare(control, control, listener, null);
339 assertEquals(-1, listener.comparingWhat);
340
341 control = control.getNextSibling();
342 test = test.getNextSibling();
343 } while (control != null);
344 }
345
346 private void assertDifferentNamespaceDetails(Node control, Node test,
347 Difference expectedDifference, boolean fatal) {
348 try {
349 engine.compareNodeBasics(control, test, listener);
350 if (fatal) {
351 fail("Expected fatal difference");
352 }
353 } catch (DifferenceEngine.DifferenceFoundException e) {
354 if (!fatal) {
355 fail("Not expecting fatal difference!");
356 }
357 }
358 assertEquals(expectedDifference.getId(), listener.comparingWhat);
359 assertEquals(fatal, listener.different);
360 resetListener();
361 }
362
363 public void testCompareNodeBasics() throws Exception {
364 String namespaceA = "http://example.org/StoneRoses";
365 String namespaceB = "http://example.org/Stone/Roses";
366 String prefixA = "music";
367 String prefixB = "cd";
368 String elemName = "nowPlaying";
369 Element control = document.createElementNS(namespaceA,
370 prefixA + ':' + elemName);
371 engine.compareNodeBasics(control, control, listener);
372
373 Element test = document.createElementNS(namespaceB,
374 prefixA + ':' + elemName);
375 assertDifferentNamespaceDetails(control, test, NAMESPACE_URI,
376 true);
377
378 test = document.createElementNS(namespaceA,
379 prefixB + ':' + elemName);
380 assertDifferentNamespaceDetails(control, test,
381 NAMESPACE_PREFIX, false);
382 }
383
384 private void assertDifferentChildren(Node control, Node test,
385 Difference expectedDifference, boolean fatal) {
386 try {
387 engine.compareHasChildNodes(control, test, listener);
388 engine.compareNodeChildren(control, test, listener, DEFAULT_ELEMENT_QUALIFIER);
389 if (fatal) {
390 fail("Expected fatal difference");
391 }
392 } catch (DifferenceEngine.DifferenceFoundException e) {
393 if (!fatal) {
394 fail("Not expecting fatal difference " +
395 listener.comparingWhat
396 + ": expected " + listener.expected
397 + " but was " + listener.actual);
398 }
399 }
400 assertEquals(expectedDifference==null ? -1 : expectedDifference.getId(),
401 listener.comparingWhat);
402 assertEquals(fatal, listener.different);
403 resetListener();
404 }
405
406 public void testCompareNodeChildren() throws Exception {
407 document = XMLUnit.buildControlDocument(
408 "<down><im standing=\"alone\"/><im><watching/>you all</im>"
409 + "<im watching=\"you\">sinking</im></down>");
410 // compare im #1 to itself
411 Node control = document.getDocumentElement().getFirstChild();
412 Node test = control;
413 assertDifferentChildren(control, control, null, false);
414
415 // compare im #1 to im #2
416 test = control.getNextSibling();
417 assertDifferentChildren(control, test, HAS_CHILD_NODES, true);
418
419 // compare im #2 to im #3
420 control = test;
421 test = control.getNextSibling();
422 assertDifferentChildren(control, test, CHILD_NODELIST_LENGTH,
423 true);
424 }
425
426 private void assertDifferentNodeLists(Node control, Node test,
427 Difference expectedDifference, boolean fatal) {
428 try {
429 engine.compareNodeList(control.getChildNodes(), test.getChildNodes(),
430 control.getChildNodes().getLength(), listener, DEFAULT_ELEMENT_QUALIFIER);
431 if (fatal) {
432 fail("Expected fatal difference");
433 }
434 } catch (DifferenceEngine.DifferenceFoundException e) {
435 if (!fatal) {
436 fail("Not expecting fatal difference!");
437 }
438 }
439 assertEquals(expectedDifference==null ? -1 : expectedDifference.getId(),
440 listener.comparingWhat);
441 assertEquals(fatal, listener.different);
442 resetListener();
443 }
444
445 public void testCompareNodeList() throws Exception {
446 document = XMLUnit.buildControlDocument(
447 "<down><im><standing/>alone</im><im><watching/>you all</im>"
448 + "<im><watching/>you sinking</im></down>");
449 // compare im #1 to itself
450 Node control = document.getDocumentElement().getFirstChild();
451 Node test = control;
452 assertDifferentNodeLists(control, test, null, false);
453
454 // compare im #1 to im #2
455 test = control.getNextSibling();
456 assertDifferentChildren(control, test, ELEMENT_TAG_NAME, true);
457
458 // compare im #2 to im #3
459 control = test;
460 test = control.getNextSibling();
461 assertDifferentChildren(control, test, TEXT_VALUE, true);
462 }
463
464 public void testCompareNodeListElements() throws Exception {
465 Element control = document.createElement("root");
466 control.appendChild(document.createElement("leafElemA"));
467 control.appendChild(document.createElement("leafElemB"));
468
469 Element test = document.createElement("root");
470 test.appendChild(document.createElement("leafElemB"));
471 test.appendChild(document.createElement("leafElemA"));
472
473 assertDifferentChildren(control, test, CHILD_NODELIST_SEQUENCE, false);
474 assertDifferentChildren(test, control, CHILD_NODELIST_SEQUENCE, false);
475 }
476
477 public void testCompareNodeListMixedContent() throws Exception {
478 Element control = document.createElement("root");
479 control.appendChild(document.createTextNode("text leaf"));
480 control.appendChild(document.createElement("leafElem"));
481
482 Element test = document.createElement("root");
483 test.appendChild(document.createElement("leafElem"));
484 test.appendChild(document.createTextNode("text leaf"));
485
486 assertDifferentChildren(control, test, CHILD_NODELIST_SEQUENCE, false);
487 assertDifferentChildren(test, control, CHILD_NODELIST_SEQUENCE, false);
488 }
489
490 public void testBasicCompare() throws Exception {
491 try {
492 engine.compare("black", "white", null, null, listener,
493 ATTR_NAME_NOT_FOUND);
494 fail("Expected difference found exception");
495 } catch (DifferenceEngine.DifferenceFoundException e) {
496 assertEquals(true, listener.different);
497 assertEquals(ATTR_NAME_NOT_FOUND.getId(), listener.comparingWhat);
498 }
499 resetListener();
500
501 try {
502 engine.compare("black", "white", null, null, listener,
503 NAMESPACE_PREFIX);
504 assertEquals(false, listener.different);
505 assertEquals(NAMESPACE_PREFIX.getId(), listener.comparingWhat);
506 } catch (Exception e) {
507 fail("Not expecting difference found exception");
508 }
509 }
510
511 public void testXpathLocation1() throws Exception {
512 String control = "<dvorak><keyboard/><composer/></dvorak>";
513 String test = "<qwerty><keyboard/></qwerty>";
514 listenToDifferences(control, test);
515 assertEquals("1st control xpath", "/dvorak[1]", listener.controlXpath);
516 assertEquals("1st test xpath", "/qwerty[1]", listener.testXpath);
517 }
518
519 public void testXpathLocation2() throws Exception {
520 String control = "<dvorak><keyboard/><composer/></dvorak>";
521 String test = "<qwerty><keyboard/></qwerty>";
522 String start = "<a>", end = "</a>";
523 listenToDifferences(start + control + end, start + test + end);
524 assertEquals("2nd control xpath", "/a[1]/dvorak[1]", listener.controlXpath);
525 assertEquals("2nd test xpath", "/a[1]/qwerty[1]", listener.testXpath);
526 }
527
528 public void testXpathLocation3() throws Exception {
529 String control = "<stuff><wood type=\"rough\"/></stuff>";
530 String test = "<stuff><wood type=\"smooth\"/></stuff>";
531 listenToDifferences(control, test);
532 assertEquals("3rd control xpath", "/stuff[1]/wood[1]/@type", listener.controlXpath);
533 assertEquals("3rd test xpath", "/stuff[1]/wood[1]/@type", listener.testXpath);
534 }
535
536 public void testXpathLocation4() throws Exception {
537 String control = "<stuff><glass colour=\"clear\"/><glass colour=\"green\"/></stuff>";
538 String test = "<stuff><glass colour=\"clear\"/><glass colour=\"blue\"/></stuff>";;
539 listenToDifferences(control, test);
540 assertEquals("4th control xpath", "/stuff[1]/glass[2]/@colour", listener.controlXpath);
541 assertEquals("4th test xpath", "/stuff[1]/glass[2]/@colour", listener.testXpath);
542 }
543
544 public void testXpathLocation5() throws Exception {
545 String control = "<stuff><wood>maple</wood><wood>oak</wood></stuff>";
546 String test = "<stuff><wood>maple</wood><wood>ash</wood></stuff>";
547 listenToDifferences(control, test);
548 assertEquals("5th control xpath", "/stuff[1]/wood[2]/text()[1]", listener.controlXpath);
549 assertEquals("5th test xpath", "/stuff[1]/wood[2]/text()[1]", listener.testXpath);
550 }
551
552 public void testXpathLocation6() throws Exception {
553 String control = "<stuff><list><wood/><glass/></list><item/></stuff>";
554 String test = "<stuff><list><wood/><glass/></list><item>description</item></stuff>";
555 listenToDifferences(control, test);
556 assertEquals("6th control xpath", "/stuff[1]/item[1]", listener.controlXpath);
557 assertEquals("6th test xpath", "/stuff[1]/item[1]", listener.testXpath);
558 }
559
560 public void testXpathLocation7() throws Exception {
561 String control = "<stuff><list><wood/></list></stuff>";
562 String test = "<stuff><list><glass/></list></stuff>";
563 listenToDifferences(control, test);
564 assertEquals("7th control xpath", "/stuff[1]/list[1]/wood[1]", listener.controlXpath);
565 assertEquals("7th test xpath", "/stuff[1]/list[1]/glass[1]", listener.testXpath);
566 }
567
568 public void testXpathLocation8() throws Exception {
569 String control = "<stuff><list><!--wood--></list></stuff>";
570 String test = "<stuff><list><!--glass--></list></stuff>";
571 listenToDifferences(control, test);
572 assertEquals("8th control xpath", "/stuff[1]/list[1]/comment()[1]", listener.controlXpath);
573 assertEquals("8th test xpath", "/stuff[1]/list[1]/comment()[1]", listener.testXpath);
574 }
575
576 public void testXpathLocation9() throws Exception {
577 String control = "<stuff><list/><?wood rough?><list/></stuff>";
578 String test = "<stuff><list/><?glass clear?><list/></stuff>";
579 listenToDifferences(control, test);
580 assertEquals("9th control xpath", "/stuff[1]/processing-instruction()[1]",
581 listener.controlXpath);
582 assertEquals("9th test xpath", "/stuff[1]/processing-instruction()[1]",
583 listener.testXpath);
584 }
585
586 public void testXpathLocation10() throws Exception {
587 String control = "<stuff><list/>list<![CDATA[wood]]></stuff>";
588 String test = "<stuff><list/>list<![CDATA[glass]]></stuff>";
589 listenToDifferences(control, test);
590 assertEquals("10th control xpath", "/stuff[1]/text()[2]",
591 listener.controlXpath);
592 assertEquals("10th test xpath", "/stuff[1]/text()[2]",
593 listener.testXpath);
594 }
595
596 public void testXpathLocation11() throws Exception {
597 String control = "<stuff><list><item/></list></stuff>";
598 String test = "<stuff><list>item text</list></stuff>";
599 listenToDifferences(control, test);
600 assertEquals("11th control xpath", "/stuff[1]/list[1]/item[1]",
601 listener.controlXpath);
602 assertEquals("11th test xpath", "/stuff[1]/list[1]/text()[1]",
603 listener.testXpath);
604 }
605
606 public void testXpathLocation12() throws Exception {
607 engine = new DifferenceEngine(PSEUDO_DETAILED_DIFF);
608 String control = "<stuff><item id=\"1\"/><item id=\"2\"/></stuff>";
609 String test = "<stuff><item id=\"1\"/></stuff>";
610 listenToDifferences(control, test);
611 assertEquals("12th control xpath", "/stuff[1]/item[2]",
612 listener.controlXpath);
613 assertEquals("12th test xpath", "/stuff[1]/item[1]",
614 listener.testXpath);
615 }
616
617 public void testXpathLocation13() throws Exception {
618 engine = new DifferenceEngine(PSEUDO_DETAILED_DIFF);
619 String control = "<stuff><item id=\"1\"/><item id=\"2\"/></stuff>";
620 String test = "<stuff><?item data?></stuff>";
621 listenToDifferences(control, test);
622 // mutiple Differences, we only see the last one, missing second element
623 assertEquals("item", listener.expected);
624 assertEquals("null", listener.actual);
625 assertEquals("13 difference type",
626 DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
627 listener.comparingWhat);
628 assertEquals("13th control xpath", "/stuff[1]/item[2]",
629 listener.controlXpath);
630 assertNull("13th test xpath", listener.testXpath);
631 }
632
633 public void testMissingChildNS() throws Exception {
634 engine = new DifferenceEngine(PSEUDO_DETAILED_DIFF);
635 String control = "<stuff xmlns=\"http://example.org/\">"
636 + "<item id=\"1\"/><item id=\"2\"/></stuff>";
637 String test = "<stuff xmlns=\"http://example.org/\"><?item data?></stuff>";
638 listenToDifferences(control, test);
639 // mutiple Differences, we only see the last one, missing second element
640 assertEquals("{http://example.org/}item", listener.expected);
641 assertEquals("null", listener.actual);
642 assertEquals("13 difference type",
643 DifferenceConstants.CHILD_NODE_NOT_FOUND_ID,
644 listener.comparingWhat);
645 assertEquals("13th control xpath", "/stuff[1]/item[2]",
646 listener.controlXpath);
647 assertNull("13th test xpath", listener.testXpath);
648 }
649
650 public void testXpathLocation14() throws Exception {
651 engine = new DifferenceEngine(PSEUDO_DETAILED_DIFF);
652 String control = "<stuff><thing id=\"1\"/><item id=\"2\"/></stuff>";
653 String test = "<stuff><item id=\"2\"/><item id=\"1\"/></stuff>";
654 listenToDifferences(control, test);
655 assertEquals("14th control xpath", "/stuff[1]/item[1]/@id",
656 listener.controlXpath);
657 assertEquals("14th test xpath", "/stuff[1]/item[2]/@id",
658 listener.testXpath);
659 }
660
661 public void testIssue1027863() throws Exception {
662 engine = new DifferenceEngine(PSEUDO_DETAILED_DIFF);
663 String control = "<stuff><item id=\"1\"><thing/></item></stuff>";
664 String test = "<stuff><item id=\"2\"/></stuff>";
665 listenToDifferences(control, test);
666 assertEquals("15th difference type",
667 DifferenceEngine.CHILD_NODE_NOT_FOUND_ID,
668 listener.comparingWhat);
669 assertEquals("15th difference control value", "thing",
670 listener.expected);
671 assertEquals("15th difference test value", "null",
672 listener.actual);
673 assertEquals("15th control xpath", "/stuff[1]/item[1]/thing[1]",
674 listener.controlXpath);
675 assertNull("15th test xpath should be null but is " + listener.testXpath,
676 listener.testXpath);
677 }
678
679 public void testNormalizeWhitespace() {
680 assertEquals("a b", DifferenceEngine.normalizeWhitespace("a\rb"));
681 assertEquals("a b", DifferenceEngine.normalizeWhitespace("a b"));
682 assertEquals("a b c d e f",
683 DifferenceEngine
684 .normalizeWhitespace("a\rb c\nd\te\r\n \tf"));
685 }
686
687 public void testAttributeSequence() throws Exception {
688 testAttributeSequence(ATTR_SEQUENCE_ID);
689 resetListener();
690 XMLUnit.setIgnoreAttributeOrder(true);
691 try {
692 testAttributeSequence(-1);
693 } finally {
694 XMLUnit.setIgnoreAttributeOrder(false);
695 }
696 }
697
698 private void testAttributeSequence(int expected) throws Exception {
699 Element control = document.createElement("foo");
700 Element test = document.createElement("foo");
701 OrderPreservingNamedNodeMap controlMap =
702 new OrderPreservingNamedNodeMap();
703 OrderPreservingNamedNodeMap testMap = new OrderPreservingNamedNodeMap();
704 for (int i = 0; i < 2; i++) {
705 int j = 1 - i;
706 Attr attrI = document.createAttribute("attr" + i);
707 attrI.setValue(String.valueOf(i));
708 Attr attrJ = document.createAttribute("attr" + j);
709 attrJ.setValue(String.valueOf(j));
710
711 control.setAttributeNode(attrI);
712 controlMap.add(attrI);
713 test.setAttributeNode(attrJ);
714 testMap.add(attrJ);
715 }
716 engine.compareElementAttributes(control, test, controlMap, testMap,
717 listener);
718 assertEquals(expected, listener.comparingWhat);
719 }
720
721 public void testAttributeSequenceNS() throws Exception {
722 testAttributeSequenceNS(ATTR_SEQUENCE_ID);
723 resetListener();
724 XMLUnit.setIgnoreAttributeOrder(true);
725 try {
726 testAttributeSequenceNS(-1);
727 } finally {
728 XMLUnit.setIgnoreAttributeOrder(false);
729 }
730 }
731
732 private void testAttributeSequenceNS(int expected) throws Exception {
733 Element control = document.createElementNS("ns", "foo");
734 Element test = document.createElementNS("ns", "foo");
735 OrderPreservingNamedNodeMap controlMap =
736 new OrderPreservingNamedNodeMap();
737 OrderPreservingNamedNodeMap testMap = new OrderPreservingNamedNodeMap();
738 for (int i = 0; i < 2; i++) {
739 int j = 1 - i;
740 Attr attrI = document.createAttributeNS("ns", "attr" + i);
741 attrI.setValue(String.valueOf(i));
742 Attr attrJ = document.createAttributeNS("ns", "attr" + j);
743 attrJ.setValue(String.valueOf(j));
744
745 control.setAttributeNode(attrI);
746 controlMap.add(attrI);
747 test.setAttributeNode(attrJ);
748 testMap.add(attrJ);
749 }
750 engine.compareElementAttributes(control, test, controlMap, testMap,
751 listener);
752 assertEquals(expected, listener.comparingWhat);
753 }
754
755 public void testExtraComment() {
756 testExtraComment(true);
757 resetListener();
758 XMLUnit.setIgnoreComments(true);
759 try {
760 testExtraComment(false);
761 } finally {
762 XMLUnit.setIgnoreComments(false);
763 }
764 }
765
766 private void testExtraComment(boolean expectDifference) {
767 Element control = document.createElement("foo");
768 Element test = document.createElement("foo");
769 Comment c = document.createComment("bar");
770 control.appendChild(c);
771 Element cChild = document.createElement("baz");
772 control.appendChild(cChild);
773 Element tChild = document.createElement("baz");
774 test.appendChild(tChild);
775 engine.compare(control, test, listener, null);
776 assertEquals(expectDifference, listener.different);
777 resetListener();
778 engine.compare(test, control, listener, null);
779 assertEquals(expectDifference, listener.different);
780 }
781
782 public void testCommentContent() {
783 testCommentContent(true);
784 resetListener();
785 XMLUnit.setIgnoreComments(true);
786 try {
787 testCommentContent(false);
788 } finally {
789 XMLUnit.setIgnoreComments(false);
790 }
791 }
792
793 private void testCommentContent(boolean expectDifference) {
794 Element control = document.createElement("foo");
795 Element test = document.createElement("foo");
796 Comment c = document.createComment("bar");
797 control.appendChild(c);
798 Comment c2 = document.createComment("baz");
799 test.appendChild(c2);
800 engine.compare(control, test, listener, null);
801 assertEquals(expectDifference, listener.different);
802 }
803
804 public void testMissingSchemaLocation() throws Exception {
805 testMissingXSIAttribute(XMLConstants
806 .W3C_XML_SCHEMA_INSTANCE_SCHEMA_LOCATION_ATTR,
807 DifferenceConstants.SCHEMA_LOCATION_ID);
808 }
809
810 public void testMissingNoNamespaceSchemaLocation() throws Exception {
811 testMissingXSIAttribute(XMLConstants
812 .W3C_XML_SCHEMA_INSTANCE_NO_NAMESPACE_SCHEMA_LOCATION_ATTR,
813 DifferenceConstants.NO_NAMESPACE_SCHEMA_LOCATION_ID);
814 }
815
816 private void testMissingXSIAttribute(String attrName,
817 int expectedDifference)
818 throws Exception {
819 Element control = document.createElement("foo");
820 control.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
821 attrName, "bar");
822 Element test = document.createElement("foo");
823 engine.compare(control, test, listener, null);
824 assertEquals(expectedDifference, listener.comparingWhat);
825 resetListener();
826 engine.compare(test, control, listener, null);
827 assertEquals(expectedDifference, listener.comparingWhat);
828 }
829
830 public void testDifferentSchemaLocation() throws Exception {
831 testDifferentXSIAttribute(XMLConstants
832 .W3C_XML_SCHEMA_INSTANCE_SCHEMA_LOCATION_ATTR,
833 DifferenceConstants.SCHEMA_LOCATION_ID);
834 }
835
836 public void testDifferentNoNamespaceSchemaLocation() throws Exception {
837 testDifferentXSIAttribute(XMLConstants
838 .W3C_XML_SCHEMA_INSTANCE_NO_NAMESPACE_SCHEMA_LOCATION_ATTR,
839 DifferenceConstants.NO_NAMESPACE_SCHEMA_LOCATION_ID);
840 }
841
842 private void testDifferentXSIAttribute(String attrName,
843 int expectedDifference)
844 throws Exception {
845 Element control = document.createElement("foo");
846 control.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
847 attrName, "bar");
848 Element test = document.createElement("foo");
849 test.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
850 attrName, "baz");
851 engine.compare(control, test, listener, null);
852 assertEquals(expectedDifference, listener.comparingWhat);
853 }
854
855 public void testMissingAttribute() throws Exception {
856 Element control = document.createElement("foo");
857 control.setAttribute("bar", "baz");
858 Element test = document.createElement("foo");
859 test.setAttribute("baz", "bar");
860 engine.compare(control, test, listener, null);
861 assertEquals(ATTR_NAME_NOT_FOUND_ID, listener.comparingWhat);
862 assertEquals("bar", listener.expected);
863 assertEquals("null", listener.actual);
864 assertEquals("/foo[1]/@bar", listener.controlXpath);
865 assertEquals("/foo[1]", listener.testXpath);
866 }
867
868 public void testMissingAttributeNS() throws Exception {
869 Element control = document.createElement("foo");
870 control.setAttributeNS("http://example.org/", "bar", "baz");
871 Element test = document.createElement("foo");
872 test.setAttributeNS("http://example.org/", "baz", "bar");
873 engine.compare(control, test, listener, null);
874 assertEquals(ATTR_NAME_NOT_FOUND_ID, listener.comparingWhat);
875 assertEquals("{http://example.org/}bar", listener.expected);
876 assertEquals("null", listener.actual);
877 assertEquals("/foo[1]/@bar", listener.controlXpath);
878 assertEquals("/foo[1]", listener.testXpath);
879 }
880
881 public void testMatchTrackerSetViaConstructor() throws Exception {
882 Element control = document.createElement("foo");
883 Element test = document.createElement("foo");
884 final int[] count = new int[1];
885 DifferenceEngine d =
886 new DifferenceEngine(new SimpleComparisonController(),
887 new MatchTracker() {
888 public void matchFound(Difference d) {
889 count[0]++;
890 }
891 });
892 d.compare(control, test, listener, null);
893 // NODE_TYPE (not null), NODE_TYPE(Element), NAMESPACE_URI(none),
894 // NAMESPACE_PREFIX(none), ELEMENT_TAG_NAME(foo),
895 // ELEMENT_NUM_ATTRIBUTE(none), HAS_CHILD_NODES(false),
896 // CHILD_NODELIST_LENGTH(0)
897 assertEquals(8, count[0]);
898 }
899
900 public void testMatchTrackerSetViaSetter() throws Exception {
901 Element control = document.createElement("foo");
902 Element test = document.createElement("foo");
903 final int[] count = new int[1];
904 engine.setMatchTracker(new MatchTracker() {
905 public void matchFound(Difference d) {
906 count[0]++;
907 }
908 });
909 engine.compare(control, test, listener, null);
910 // NODE_TYPE (not null), NODE_TYPE(Element), NAMESPACE_URI(none),
911 // NAMESPACE_PREFIX(none), ELEMENT_TAG_NAME(foo),
912 // ELEMENT_NUM_ATTRIBUTE(none), HAS_CHILD_NODES(false),
913 // CHILD_NODELIST_LENGTH(0)
914 assertEquals(8, count[0]);
915 }
916
917 /**
918 * @see http://sourceforge.net/forum/forum.php?thread_id=3284504&forum_id=73274
919 */
920 public void testNamespaceAttributeDifferences() throws Exception {
921 String control = "<?xml version = \"1.0\" encoding = \"UTF-8\"?>"
922 + "<ns0:Message xmlns:ns0 = \"http://mynamespace\">"
923 + "<ns0:EventHeader>"
924 + "<ns0:EventID>9999</ns0:EventID>"
925 + "<ns0:MessageID>1243409665297</ns0:MessageID>"
926 + "<ns0:MessageVersionID>1.0</ns0:MessageVersionID>"
927 + "<ns0:EventName>TEST-EVENT</ns0:EventName>"
928 + "<ns0:BWDomain>TEST</ns0:BWDomain>"
929 + "<ns0:DateTimeStamp>2009-01-01T12:00:00</ns0:DateTimeStamp>"
930 + "<ns0:SchemaPayloadRef>anything</ns0:SchemaPayloadRef>"
931 + "<ns0:MessageURI>anything</ns0:MessageURI>"
932 + "<ns0:ResendFlag>F</ns0:ResendFlag>"
933 + "</ns0:EventHeader>"
934 + "<ns0:EventBody>"
935 + "<ns0:XMLContent>"
936 + "<xyz:root xmlns:xyz=\"http://test.com/xyz\">"
937 + "<xyz:test1>A</xyz:test1>"
938 + "<xyz:test2>B</xyz:test2>"
939 + "</xyz:root>"
940 + "</ns0:XMLContent>"
941 + "</ns0:EventBody>"
942 + "</ns0:Message>";
943 String test =
944 "<abc:Message xmlns:abc=\"http://mynamespace\" xmlns:xyz=\"http://test.com/xyz\">"
945 + "<abc:EventHeader>"
946 + "<abc:EventID>9999</abc:EventID>"
947 + "<abc:MessageID>1243409665297</abc:MessageID>"
948 + "<abc:MessageVersionID>1.0</abc:MessageVersionID>"
949 + "<abc:EventName>TEST-EVENT</abc:EventName>"
950 + "<abc:BWDomain>TEST</abc:BWDomain>"
951 + "<abc:DateTimeStamp>2009-01-01T12:00:00</abc:DateTimeStamp>"
952 + "<abc:SchemaPayloadRef>anything</abc:SchemaPayloadRef>"
953 + "<abc:MessageURI>anything</abc:MessageURI>"
954 + "<abc:ResendFlag>F</abc:ResendFlag>"
955 + "</abc:EventHeader>"
956 + "<abc:EventBody>"
957 + "<abc:XMLContent>"
958 + "<xyz:root>"
959 + "<xyz:test1>A</xyz:test1>"
960 + "<xyz:test2>B</xyz:test2>"
961 + "</xyz:root>"
962 + "</abc:XMLContent>"
963 + "</abc:EventBody>"
964 + "</abc:Message>";
965 listenToDifferences(control, test);
966 assertFalse(listener.different);
967 }
968
969
970 /**
971 * @see https://sourceforge.net/forum/message.php?msg_id=4817456
972 */
973 public void testForumMessage4817456() throws Exception {
974 String control = "<doc>"
975 + "<id>123</id>"
976 + "<remarks>a</remarks>"
977 + "<remarks>b</remarks>"
978 + "<remarks>c</remarks>"
979 + "<remarks>d</remarks>"
980 + "<others>1</others>"
981 + "<others>2</others>"
982 + "<others>3</others>"
983 + "</doc>";
984 String test = "<doc>"
985 + "<id>123</id>"
986 + "<remarks>a</remarks>"
987 + "<remarks>b</remarks>"
988 + "<remarks>c</remarks>"
989 + "<remarks>d</remarks>"
990 + "<remarks>e</remarks>"
991 + "<others>2</others>"
992 + "<others>3</others>"
993 + "</doc>";
994
995 Document controlDoc = XMLUnit.buildControlDocument(control);
996 Document testDoc = XMLUnit.buildTestDocument(test);
997 engine.compare(controlDoc, testDoc, listener,
998 new ElementNameAndTextQualifier());
999 assertTrue(listener.different);
1000 assertEquals(DifferenceConstants.ELEMENT_TAG_NAME_ID,
1001 listener.comparingWhat);
1002 }
1003
1004 private void listenToDifferences(String control, String test)
1005 throws SAXException, IOException {
1006 Document controlDoc = XMLUnit.buildControlDocument(control);
1007 Document testDoc = XMLUnit.buildTestDocument(test);
1008 engine.compare(controlDoc, testDoc, listener, DEFAULT_ELEMENT_QUALIFIER);
1009 }
1010
1011
1012 private void resetListener() {
1013 listener = new CollectingDifferenceListener();
1014 }
1015
1016 public void setUp() throws Exception {
1017 resetListener();
1018 engine = new DifferenceEngine(PSEUDO_DIFF);
1019 DocumentBuilder documentBuilder = XMLUnit.newControlParser();
1020 document = documentBuilder.newDocument();
1021 }
1022
1023 private class SimpleComparisonController implements ComparisonController {
1024 public boolean haltComparison(Difference afterDifference) {
1025 return !afterDifference.isRecoverable();
1026 }
1027 }
1028
1029 private class NeverHaltingComparisonController implements ComparisonController {
1030 public boolean haltComparison(Difference afterDifference) {
1031 return false;
1032 }
1033 }
1034
1035 private class CollectingDifferenceListener implements DifferenceListener {
1036 public String expected;
1037 public String actual;
1038 public Node control;
1039 public Node test;
1040 public int comparingWhat = -1;
1041 public boolean different = false;
1042 public boolean nodesSkipped = false;
1043 public String controlXpath;
1044 public String testXpath;
1045 private boolean tracing = false;
1046 public int differenceFound(Difference difference) {
1047 if (tracing) {
1048 System.out.println(difference.toString());
1049 }
1050 assertNotNull("difference not null", difference);
1051 assertNotNull("control node detail not null", difference.getControlNodeDetail());
1052 assertNotNull("test node detail not null", difference.getTestNodeDetail());
1053 this.expected = difference.getControlNodeDetail().getValue();
1054 this.actual = difference.getTestNodeDetail().getValue();
1055 this.control = difference.getControlNodeDetail().getNode();
1056 this.test = difference.getTestNodeDetail().getNode();
1057 this.comparingWhat = difference.getId();
1058 this.different = !difference.isRecoverable();
1059 this.controlXpath = difference.getControlNodeDetail().getXpathLocation();
1060 this.testXpath = difference.getTestNodeDetail().getXpathLocation();
1061 return RETURN_ACCEPT_DIFFERENCE;
1062 }
1063 public void skippedComparison(Node control, Node test) {
1064 nodesSkipped = true;
1065 }
1066 public void setTrace(boolean active) {
1067 tracing = active;
1068 }
1069 }
1070
1071 private class OrderPreservingNamedNodeMap implements NamedNodeMap {
1072 private ArrayList/* Attr */ nodes = new ArrayList();
1073
1074 void add(Attr attr) {
1075 nodes.add(attr);
1076 }
1077
1078 public int getLength() { return nodes.size(); }
1079 public Node item(int index) { return (Node) nodes.get(index); }
1080
1081 public Node getNamedItem(String name) {
1082 for (Iterator iter = nodes.iterator(); iter.hasNext(); ) {
1083 Attr a = (Attr) iter.next();
1084 if (a.getName().equals(name)) {
1085 return a;
1086 }
1087 }
1088 return null;
1089 }
1090
1091 public Node getNamedItemNS(String ns, String localName) {
1092 for (Iterator iter = nodes.iterator(); iter.hasNext(); ) {
1093 Attr a = (Attr) iter.next();
1094 if (a.getLocalName().equals(localName)
1095 && a.getNamespaceURI().equals(ns)) {
1096 return a;
1097 }
1098 }
1099 return null;
1100 }
1101
1102 // not implemented, not needed in our case
1103 public Node removeNamedItem(String n) {
1104 return fail();
1105 }
1106 public Node removeNamedItemNS(String n1, String n2) {
1107 return fail();
1108 }
1109 public Node setNamedItem(Node n) {
1110 return fail();
1111 }
1112 public Node setNamedItemNS(Node n) {
1113 return fail();
1114 }
1115 private Node fail() {
1116 throw new RuntimeException("not implemented");
1117 }
1118 }
1119 }
1120
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.InputStreamReader;
43 import java.io.OutputStreamWriter;
44
45 import junit.framework.TestCase;
46 import junit.framework.TestSuite;
47
48 /**
49 * JUnit test for DoctypeInputStream
50 */
51 public class test_DoctypeInputStream extends AbstractDoctypeTests {
52
53 private File testFile;
54
55 public void tearDown() {
56 if (testFile != null) {
57 testFile.delete();
58 }
59 }
60
61 private FileInputStream testDocument(String content)
62 throws IOException {
63 testFile = File.createTempFile("xmlunit_", ".xml");
64 FileOutputStream fos = new FileOutputStream(testFile);
65 OutputStreamWriter w = new OutputStreamWriter(fos, "ISO-8859-1");
66 w.write(content);
67 w.close();
68
69 return new FileInputStream(testFile);
70 }
71
72 private static String readFully(DoctypeInputStream dis)
73 throws IOException {
74 StringBuffer buf = new StringBuffer();
75 char[] ch = new char[1024];
76 int numChars;
77 InputStreamReader reader =
78 new InputStreamReader(dis, "ISO-8859-1");
79 while ((numChars = reader.read(ch))!=-1) {
80 buf.append(ch, 0, numChars);
81 }
82 return buf.toString();
83 }
84
85 protected void assertEquals(String expected, String input, String docType,
86 String systemId) throws IOException {
87 FileInputStream fis = null;
88 try {
89 fis = testDocument(input);
90 DoctypeInputStream doctypeInputStream =
91 new DoctypeInputStream(fis, "ISO-8859-1", docType, systemId);
92
93 assertEquals(expected, readFully(doctypeInputStream));
94 } finally {
95 if (fis != null) {
96 fis.close();
97 }
98 }
99 }
100
101 public void testGetContent() throws IOException {
102 String source = "WooPDeDoO!\nGooRanga!\n plIng! ";
103 DoctypeInputStream dis =
104 new DoctypeInputStream(new java.io.StringBufferInputStream(source),
105 null, "nonsense", "words");
106 assertEquals(source, dis.getContent(null));
107 // can get content indefinitely from this stream
108 assertEquals(source, dis.getContent("UTF-8"));
109 }
110
111 public test_DoctypeInputStream(String name) {
112 super(name);
113 }
114 }
115
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.IOException;
39 import java.io.StringReader;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 /**
45 * JUnit test for DoctypeReader
46 */
47 public class test_DoctypeReader extends AbstractDoctypeTests {
48 private DoctypeReader doctypeReader;
49 private StringReader sourceReader;
50 private static final String NEWLINE = System.getProperty("line.separator");
51
52 public void testGetContent() throws IOException {
53 String source = "WooPDeDoO!" + NEWLINE + "GooRanga!"
54 + NEWLINE + " plIng! ";
55 sourceReader = new StringReader(source);
56 doctypeReader = new DoctypeReader(sourceReader,
57 "nonsense", "words");
58 assertEquals(source, doctypeReader.getContent());
59 // can get content indefinitely from this reader
60 assertEquals(source, doctypeReader.getContent());
61 }
62
63 private void initDummyDoctypeReader() {
64 sourceReader = new StringReader("yabba");
65 doctypeReader = new DoctypeReader(sourceReader,
66 "yabba", "don\'t");
67 }
68
69 public void testReplaceDoctypeInternalDTD() {
70 initDummyDoctypeReader();
71 StringBuffer buf = new StringBuffer(test_Constants.CHUCK_JONES_RIP_DTD_DECL);
72 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">",
73 doctypeReader.replaceDoctype(buf, "ni", "shrubbery"));
74 }
75
76 public void testReplaceDoctypeExternalDTD() {
77 initDummyDoctypeReader();
78 StringBuffer buf = new StringBuffer(
79 "<! DOCTYPE PUBLIC \"yak\" SYSTEM \"llama\">");
80 assertEquals("<! DOCTYPE ni SYSTEM \"shrubbery\">",
81 doctypeReader.replaceDoctype(buf, "ni", "shrubbery"));
82 }
83
84 public void testReplaceDoctypeNoDTD() {
85 initDummyDoctypeReader();
86 StringBuffer buf = new StringBuffer(NO_DTD);
87 assertEquals("<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD,
88 doctypeReader.replaceDoctype(buf, "ni", "shrubbery"));
89 }
90
91 public void testReplaceDoctypeNoDTDButXMLDecl() {
92 initDummyDoctypeReader();
93 StringBuffer buf = new StringBuffer(test_Constants.XML_DECLARATION
94 + NO_DTD);
95 assertEquals(test_Constants.XML_DECLARATION +
96 "<!DOCTYPE ni SYSTEM \"shrubbery\">" + NO_DTD,
97 doctypeReader.replaceDoctype(buf, "ni", "shrubbery"));
98 }
99
100 private static String readFully(DoctypeReader reader)
101 throws IOException {
102 StringBuffer buf = new StringBuffer();
103 char[] ch = new char[1024];
104 int numChars;
105 while ((numChars = reader.read(ch))!=-1) {
106 buf.append(ch, 0, numChars);
107 }
108 return buf.toString();
109 }
110
111 protected void assertEquals(String expected, String input, String docType,
112 String systemId) throws IOException {
113 DoctypeReader doctypeReader =
114 new DoctypeReader(new StringReader(expected), docType,
115 systemId);
116 assertEquals(expected, readFully(doctypeReader));
117 }
118
119 public test_DoctypeReader(String name) {
120 super(name);
121 }
122 }
123
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 /**
45 * JUnit testcase for ElementNameAndAttributeQualifier
46 * @see test_Diff#testRepeatedElementNamesWithAttributeQualification()
47 */
48 public class test_ElementNameAndAttributeQualifier extends TestCase {
49 private Document document;
50 private ElementNameAndAttributeQualifier elementNameAndAttributeQualifier;
51 private static final String TAG_NAME = "qwerty";
52
53 public void testSingleQualifyingAttribute() throws Exception {
54 final String attrName = "id";
55
56 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier();
57 testAssertionsFor(attrName, new boolean[] {false, false});
58
59 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier(attrName);
60 testAssertionsFor(attrName, new boolean[] {true, true});
61 }
62
63 private void testAssertionsFor(String attrName, boolean[] expectedValues) throws Exception {
64 Element control = document.createElement(TAG_NAME);
65 control.setAttribute(attrName, "1");
66
67 Element test = document.createElement(TAG_NAME);
68 assertFalse("qwerty id 1 not comparable to qwerty with no attributes",
69 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
70
71 test.setAttribute(attrName, "1");
72 assertTrue("qwerty id 1 comparable to qwerty id 1",
73 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
74
75 control.setAttribute("uiop","true");
76 assertEquals("qwerty id 1 && uiop comparable to qwerty id 1", expectedValues[0],
77 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
78
79 test.setAttribute("uiop", "false");
80 assertEquals("qwerty id 1 && uiop comparable to qwerty id 1 && !uiop", expectedValues[1],
81 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
82
83 test.setAttribute(attrName, "2");
84 assertFalse("qwerty id 1 && uiop NOT comparable to qwerty id 2 && !uiop",
85 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
86 }
87
88 public void testMultipleQualifyingAttributes() throws Exception {
89 final String[] attrNames = {"id", "uid"};
90
91 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier();
92 testAssertionsFor(attrNames, new boolean[] {false, false});
93
94 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier(attrNames);
95 testAssertionsFor(attrNames, new boolean[] {true, true});
96 }
97
98 private void testAssertionsFor(String[] attrNames, boolean[] expectedValues) throws Exception {
99 Element control = document.createElement(TAG_NAME);
100 for (int i=0; i < attrNames.length; ++i) {
101 control.setAttribute(attrNames[i], "1");
102 }
103
104 Element test = document.createElement(TAG_NAME);
105 assertFalse("qwerty id/uid 1 not comparable to qwerty with no attributes",
106 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
107
108 for (int i=0; i < attrNames.length; ++i) {
109 test.setAttribute(attrNames[i], "1");
110 }
111
112 assertTrue("qwerty id/uid 1 comparable to qwerty id/uid 1",
113 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
114
115 control.setAttribute("oid", "0x2394b3456df");
116 assertEquals("qwerty id/uid 1 with oid comparable to qwerty id/uid 1",
117 expectedValues[0],
118 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
119
120 test.setAttribute("oid", "0xfd6543b4932");
121 assertEquals("qwerty id/uid 1 with oid comparable to qwerty id/uid 1 with different oid",
122 expectedValues[1],
123 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
124
125 test.setAttribute(attrNames[0], "2");
126 assertFalse("qwerty id/uid 1 not comparable to qwerty id 2 /uid 1",
127 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
128
129 test.setAttribute(attrNames[0], "1");
130 test.setAttribute(attrNames[1], "2");
131 assertFalse("qwerty id/uid 1 not comparable to qwerty id 1 /uid 2",
132 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
133
134 test.setAttribute(attrNames[0], "2");
135 assertFalse("qwerty id/uid 1 not comparable to qwerty id/uid 2",
136 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
137 }
138
139 public void testNamespacedQualifyingAttribute() throws Exception {
140 final String attrName = "id";
141 final String nsURI = "http://xmlunit.sourceforge.net/tests";
142
143 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier();
144 testAssertionsFor(attrName, nsURI, new boolean[] {false, false});
145
146 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier(attrName);
147 testAssertionsFor(attrName, nsURI, new boolean[] {true, true});
148 }
149
150 private void testAssertionsFor(String attrName, String nsURI, boolean[] expectedValues)
151 throws Exception {
152 Element control = document.createElement(TAG_NAME);
153 control.setAttributeNS(nsURI, attrName, "1");
154
155 Element test = document.createElement(TAG_NAME);
156 assertFalse("qwerty id 1 not comparable to qwerty with no attributes",
157 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
158
159 test.setAttributeNS(nsURI, attrName, "1");
160 assertTrue("qwerty id 1 comparable to qwerty id 1",
161 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
162
163 String otherNsURI = nsURI + "/2";
164 test.setAttributeNS(otherNsURI, attrName, "2");
165 assertTrue("qwerty id 1 comparable to qwerty id 1 and other-NS id 2",
166 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
167
168 control.setAttributeNS(nsURI, "uiop","true");
169 assertEquals("qwerty id 1 && uiop comparable to qwerty id 1", expectedValues[0],
170 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
171
172 test.setAttributeNS(nsURI, "uiop", "false");
173 assertEquals("qwerty id 1 && uiop comparable to qwerty id 1 && !uiop", expectedValues[1],
174 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
175
176 test.setAttributeNS(nsURI, attrName, "2");
177 assertFalse("qwerty id 1 && uiop NOT comparable to qwerty id 2 && !uiop",
178 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
179 }
180
181 // Bug 952920
182 public void testQualifyingAttributeMissingInControl() throws Exception {
183 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier("foo");
184 assertQualifyingAttributeMissingInControl();
185 elementNameAndAttributeQualifier = new ElementNameAndAttributeQualifier(new String[] {"foo", "bar"});
186 assertQualifyingAttributeMissingInControl();
187 }
188
189 private void assertQualifyingAttributeMissingInControl()
190 throws Exception {
191 Element control = document.createElement(TAG_NAME);
192
193 Element test = document.createElement(TAG_NAME);
194 assertTrue("empty elements match",
195 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
196
197 test.setAttribute("id", "1");
198 assertTrue("extra attribute on test matches",
199 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
200
201 control.setAttribute("id", "2");
202 assertTrue("differerent values for extra attribute still matches",
203 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
204
205 control.setAttribute("uid", "1");
206 assertTrue("extra attribute on control matches",
207 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
208
209 test.setAttribute("foo", "1");
210 assertFalse("no match if attribute is present in test",
211 elementNameAndAttributeQualifier.qualifyForComparison(control, test));
212 }
213
214 /**
215 * @see https://sourceforge.net/forum/forum.php?thread_id=1135716&forum_id=73274l
216 */
217 public void testHelpForumThread1135716() throws Exception {
218 String control = "<class id=\"c0\"> "
219 + "<method id=\"c0_m0\"> "
220 + "<dependency_info stmtId=\"c0_m0_s4\"> "
221 + "<dependent tid=\"c3_m1_s18\"/> "
222 + "<dependent tid=\"c3_m1_s32\"/> "
223 + "<dependent tid=\"c3_m1_s26\"/> "
224 + "</dependency_info> "
225 + "</method> "
226 + "</class>";
227 String test = "<class id=\"c0\"> "
228 + "<method id=\"c0_m0\"> "
229 + "<dependency_info stmtId=\"c0_m0_s4\"> "
230 + "<dependent tid=\"c3_m1_s32\"/> "
231 + "<dependent tid=\"c3_m1_s18\"/> "
232 + "<dependent tid=\"c3_m1_s26\"/> "
233 + "</dependency_info> "
234 + "</method> "
235 + "</class>";
236 Diff d = new Diff(control, test);
237 assertFalse(d.similar());
238
239 // reset
240 d = new Diff(control, test);
241 d.overrideElementQualifier(new ElementNameAndAttributeQualifier());
242 assertTrue(d.similar());
243 }
244
245 public void setUp() throws Exception {
246 document = XMLUnit.newControlParser().newDocument();
247 }
248
249 public static TestSuite suite() {
250 return new TestSuite(test_ElementNameAndAttributeQualifier.class);
251 }
252
253 /**
254 * Constructor for test_ElementNameAndAttributeQualifier.
255 * @param name
256 */
257 public test_ElementNameAndAttributeQualifier(String name) {
258 super(name);
259 }
260
261 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 /**
45 * JUnit testcase for ElementNameAndTextQualifier
46 * @see test_Diff#testRepeatedElementNamesWithTextQualification()
47 */
48 public class test_ElementNameAndTextQualifier extends TestCase {
49 private static final String TAG_NAME = "tagYoureIt";
50 private static final String TEXT_A = "textA";
51 private static final String TEXT_B = "textB";
52 private Document document;
53 private ElementNameAndTextQualifier elementNameAndTextQualifier;
54
55 public void testSingleTextValue() throws Exception {
56 Element control = document.createElement(TAG_NAME);
57 control.appendChild(document.createTextNode(TEXT_A));
58
59 Element test = document.createElement(TAG_NAME);
60
61 assertFalse("control text not comparable to empty text",
62 elementNameAndTextQualifier.qualifyForComparison(control, test));
63
64 test.appendChild(document.createTextNode(TEXT_A));
65 assertTrue("control textA comparable to test textA",
66 elementNameAndTextQualifier.qualifyForComparison(control, test));
67
68 test = document.createElement(TAG_NAME);
69
70 test.appendChild(document.createTextNode(TEXT_B));
71 assertFalse("control textA not comparable to test textB",
72 elementNameAndTextQualifier.qualifyForComparison(control, test));
73 }
74
75 public void testMultipleTextValues() throws Exception {
76 Element control = document.createElement(TAG_NAME);
77 control.appendChild(document.createTextNode(TEXT_A));
78 control.appendChild(document.createTextNode(TEXT_B));
79
80 Element test = document.createElement(TAG_NAME);
81 test.appendChild(document.createTextNode(TEXT_A + TEXT_B));
82 assertTrue("denormalised control text comparable to normalised test text",
83 elementNameAndTextQualifier.qualifyForComparison(control, test));
84 }
85
86 public void setUp() throws Exception {
87 document = XMLUnit.newControlParser().newDocument();
88 elementNameAndTextQualifier = new ElementNameAndTextQualifier();
89 }
90
91 /**
92 * Constructor for test_ElementNameAndTextQualifier.
93 */
94 public test_ElementNameAndTextQualifier() {
95 super();
96 }
97
98 /**
99 * Constructor for test_ElementNameAndTextQualifier.
100 * @param name
101 */
102 public test_ElementNameAndTextQualifier(String name) {
103 super(name);
104 }
105
106 public static TestSuite suite() {
107 return new TestSuite(test_ElementNameAndTextQualifier.class);
108 }
109 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 /**
45 * JUnit testcase for ElementNameEqualifier
46 */
47 public class test_ElementNameQualifier extends TestCase {
48 private Document document;
49 private ElementNameQualifier elementNameQualifier;
50 private static final String NAME_A = "nameA";
51 private static final String NAME_B = "nameB";
52
53 public void testElementsNoNamespace() throws Exception {
54 Element control = document.createElement(NAME_A);
55 Element test = document.createElement(NAME_A);
56 assertTrue("nameA comparable to nameA", elementNameQualifier.qualifyForComparison(control, test));
57
58 test = document.createElement(NAME_B);
59 assertFalse("nameA not comparable to nameB", elementNameQualifier.qualifyForComparison(control, test));
60 }
61
62 public void testElementsWithNamespace() throws Exception {
63 String anURI = "gopher://example.com";
64 String qnameQualifierA = "qnq:";
65
66 Element control = document.createElementNS(anURI, qnameQualifierA + NAME_A);
67 Element test = document.createElementNS(anURI, qnameQualifierA + NAME_A);
68 assertTrue("qualified nameA comparable to nameA", elementNameQualifier.qualifyForComparison(control, test));
69
70 test = document.createElementNS(anURI, qnameQualifierA + NAME_B);
71 assertFalse("qualified nameA not comparable to nameB", elementNameQualifier.qualifyForComparison(control, test));
72
73 String qnameQualifierB = "pgp:";
74 test = document.createElementNS(anURI, qnameQualifierB + NAME_A);
75 assertTrue("qualified nameA comparable to requalified nameA", elementNameQualifier.qualifyForComparison(control, test));
76
77 test = document.createElementNS(anURI, qnameQualifierB + NAME_B);
78 assertFalse("qualified nameA not comparable to requalifiednameB",
79 elementNameQualifier.qualifyForComparison(control, test));
80
81 String anotherURI = "ftp://example.com";
82 test = document.createElementNS(anotherURI, qnameQualifierA + NAME_A);
83 assertFalse("qualified nameA not comparable to anotherURI nameA",
84 elementNameQualifier.qualifyForComparison(control, test));
85
86 test = document.createElementNS(anotherURI, qnameQualifierB + NAME_A);
87 assertFalse("qualified nameA comparable to requalified-anotherURI nameA",
88 elementNameQualifier.qualifyForComparison(control, test));
89
90 test = document.createElementNS(anotherURI, qnameQualifierB + NAME_B);
91 assertFalse("qualified nameA not comparable to requalified-anotherURI nameB",
92 elementNameQualifier.qualifyForComparison(control, test));
93 }
94
95
96 public void setUp() throws Exception {
97 document = XMLUnit.newControlParser().newDocument();
98 elementNameQualifier = new ElementNameQualifier();
99 }
100
101 public static TestSuite suite() {
102 return new TestSuite(test_ElementNameQualifier.class);
103 }
104
105 public test_ElementNameQualifier(String name) {
106 super(name);
107 }
108
109 }
0 /*
1 ******************************************************************
2 Copyright (c) 2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.Arrays;
39 import junit.framework.TestCase;
40 import org.w3c.dom.Node;
41
42 /**
43 * @see http://sf.net/forum/message.php?msg_id=4406472
44 */
45 public class test_ForumMessage4406472 extends TestCase {
46
47 private static final String doc1 =
48 "<pub:Book xmlns:pub=\"http://www.publishing.org\" date=\"2007-01-01\">"
49 + " <pub:Title>String</pub:Title>"
50 + " <pub:Author>String</pub:Author>"
51 + " <pub:ISBN>String</pub:ISBN>"
52 + " <pub:Publisher>String</pub:Publisher>"
53 + " <pub:Price>34.50</pub:Price>"
54 + "</pub:Book>";
55
56 private static final String doc2 =
57 "<p:Book xmlns:p=\"http://www.publishing.org\" date=\"1900-01-01\">"
58 + " <p:Title>Bla</p:Title>"
59 + " <p:Author>Bla</p:Author>"
60 + " <p:ISBN>Bla</p:ISBN>"
61 + " <p:Publisher>Bla</p:Publisher>"
62 + " <p:Price>0.00</p:Price>"
63 + "</p:Book>";
64
65 private class OriginalDifferenceListener implements DifferenceListener {
66 private int[] IGNORE = new int[] {
67 DifferenceConstants.ATTR_VALUE_ID,
68 DifferenceConstants.ATTR_VALUE_EXPLICITLY_SPECIFIED_ID,
69 DifferenceConstants.TEXT_VALUE_ID,
70 DifferenceConstants.NAMESPACE_PREFIX_ID,
71 DifferenceConstants.NAMESPACE_URI_ID
72 };
73
74 public int differenceFound(Difference difference) {
75 Arrays.sort(IGNORE);
76 return Arrays.binarySearch(IGNORE, difference.getId()) >= 0
77 ? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
78 : RETURN_ACCEPT_DIFFERENCE;
79 }
80
81 public void skippedComparison(Node control, Node test) {
82 }
83 }
84
85 private class ModifiedDifferenceListener implements DifferenceListener {
86 private int[] IGNORE = new int[] {
87 DifferenceConstants.ATTR_VALUE_ID,
88 DifferenceConstants.ATTR_VALUE_EXPLICITLY_SPECIFIED_ID,
89 DifferenceConstants.TEXT_VALUE_ID,
90 DifferenceConstants.NAMESPACE_PREFIX_ID,
91 };
92
93 private ModifiedDifferenceListener() {
94 Arrays.sort(IGNORE);
95 }
96
97 public int differenceFound(Difference difference) {
98 return Arrays.binarySearch(IGNORE, difference.getId()) >= 0
99 ? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
100 : difference.isRecoverable()
101 ? RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR
102 : RETURN_ACCEPT_DIFFERENCE;
103 }
104
105 public void skippedComparison(Node control, Node test) {
106 }
107 }
108
109 public void testOriginal() throws Exception {
110 Diff d = new Diff(doc1, doc2);
111 d.overrideDifferenceListener(new OriginalDifferenceListener());
112 assertTrue(d.toString(), d.similar());
113 }
114
115 public void testModified() throws Exception {
116 Diff d = new Diff(doc1, doc2);
117 d.overrideDifferenceListener(new ModifiedDifferenceListener());
118 assertTrue(d.toString(), d.similar());
119 }
120 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import junit.framework.TestSuite;
39
40 import org.w3c.dom.Document;
41
42 /**
43 * JUnit test for HTMLDocumentBuilder
44 */
45 public class test_HTMLDocumentBuilder extends XMLTestCase {
46 private static final String xHtml =
47 "<html><head><title>test</title></head>" +
48 "<body><h1>hello</h1><p>world</p><hr/><div><img src=\"foo.bar\"/>" +
49 "<ul><li>one</li><li>two</li></ul></div></body></html>";
50 private Document xHtmlDocument;
51 private HTMLDocumentBuilder parser;
52 private TolerantSaxDocumentBuilder builder;
53
54 public void testParseGoodHtml() throws Exception {
55 assertParsedDocumentEqual(xHtmlDocument, xHtml);
56 assertEquals(parser.getTrace(),-1, parser.getTrace().indexOf("WARNING"));
57 }
58
59 public void testParseOldHtml() throws Exception {
60 String oldHTML=
61 "<html><head><title>test</title></head>" +
62 "<body><h1>hello</h1><p>world<hr><div><img src=\"foo.bar\">" +
63 "<ul><li>one<li>two</ul></div></body></html>";
64 assertParsedDocumentEqual(xHtmlDocument, oldHTML);
65 assertEquals(parser.getTrace(),-1, parser.getTrace().indexOf("WARNING"));
66 }
67
68 public void testParsePoorHtml() throws Exception {
69 String poorHTML=
70 "<html><head><title>test</title></head>" +
71 "<body><h1>hello</h1><p>world<hr><div><img src=\"foo.bar\">" +
72 "<ul><li>one<li>two";
73 assertParsedDocumentEqual(xHtmlDocument, poorHTML);
74 assertEquals(parser.getTrace(),-1, parser.getTrace().indexOf("WARNING"));
75 }
76
77 private void assertParsedDocumentEqual(Document control, String test)
78 throws Exception {
79 assertXMLEqual(control, parser.parse(test));
80 }
81
82 public test_HTMLDocumentBuilder(String name) {
83 super(name);
84 }
85
86 public void setUp() throws Exception {
87 xHtmlDocument = XMLUnit.buildControlDocument(xHtml);
88 builder = new TolerantSaxDocumentBuilder(XMLUnit.newTestParser());
89 parser = new HTMLDocumentBuilder(builder);
90
91 }
92 public static TestSuite suite() {
93 return new TestSuite(test_HTMLDocumentBuilder.class);
94 }
95 }
96
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2008,2013 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.Iterator;
39 import java.util.List;
40
41 import junit.framework.TestCase;
42
43 /**
44 * @author TimBacon
45 */
46 public class test_IgnoreTextAndAttributeValuesDifferenceListener
47 extends TestCase {
48 private DifferenceListener listener;
49 public void testDifferenceFound() {
50 assertCorrectInterpretation(
51 DifferenceConstants.ATTR_NAME_NOT_FOUND,
52 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
53 assertCorrectInterpretation(
54 DifferenceConstants.ATTR_SEQUENCE,
55 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
56 assertCorrectInterpretation(
57 DifferenceConstants.ATTR_VALUE,
58 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR);
59 assertCorrectInterpretation(
60 DifferenceConstants.ATTR_VALUE_EXPLICITLY_SPECIFIED,
61 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR);
62 assertCorrectInterpretation(
63 DifferenceConstants.CDATA_VALUE,
64 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
65 assertCorrectInterpretation(
66 DifferenceConstants.CHILD_NODELIST_LENGTH,
67 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
68 assertCorrectInterpretation(
69 DifferenceConstants.CHILD_NODELIST_SEQUENCE,
70 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
71 assertCorrectInterpretation(
72 DifferenceConstants.COMMENT_VALUE,
73 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
74 assertCorrectInterpretation(
75 DifferenceConstants.DOCTYPE_NAME,
76 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
77 assertCorrectInterpretation(
78 DifferenceConstants.DOCTYPE_PUBLIC_ID,
79 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
80 assertCorrectInterpretation(
81 DifferenceConstants.DOCTYPE_SYSTEM_ID,
82 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
83 assertCorrectInterpretation(
84 DifferenceConstants.ELEMENT_NUM_ATTRIBUTES,
85 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
86 assertCorrectInterpretation(
87 DifferenceConstants.ELEMENT_TAG_NAME,
88 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
89 assertCorrectInterpretation(
90 DifferenceConstants.HAS_CHILD_NODES,
91 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
92 assertCorrectInterpretation(
93 DifferenceConstants.HAS_DOCTYPE_DECLARATION,
94 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
95 assertCorrectInterpretation(
96 DifferenceConstants.NAMESPACE_PREFIX,
97 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
98 assertCorrectInterpretation(
99 DifferenceConstants.NAMESPACE_URI,
100 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
101 assertCorrectInterpretation(
102 DifferenceConstants.NODE_TYPE,
103 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
104 assertCorrectInterpretation(
105 DifferenceConstants.PROCESSING_INSTRUCTION_DATA,
106 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
107 assertCorrectInterpretation(
108 DifferenceConstants.PROCESSING_INSTRUCTION_TARGET,
109 DifferenceListener.RETURN_ACCEPT_DIFFERENCE);
110 assertCorrectInterpretation(
111 DifferenceConstants.TEXT_VALUE,
112 DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR);
113 }
114
115 private void assertCorrectInterpretation(
116 Difference difference, int returnValue) {
117 assertEquals(difference.toString(),
118 returnValue,
119 listener.differenceFound(difference));
120 }
121
122 public void testClassInUse() throws Exception {
123 String control = "<clouds><cloud name=\"cumulus\" rain=\"maybe\">fluffy</cloud></clouds>";
124 String similarTest = "<clouds><cloud name=\"cirrus\" rain=\"no\">wispy</cloud></clouds>";
125
126 Diff diff = new Diff(control, similarTest);
127 diff.overrideDifferenceListener(listener);
128 assertTrue("similar " + diff.toString(),
129 diff.similar());
130 assertTrue("but not identical " + diff.toString(),
131 !diff.identical());
132
133 DetailedDiff detailedDiff = new DetailedDiff(
134 new Diff(control, similarTest));
135 assertEquals("2 attribute and 1 text values",
136 3, detailedDiff.getAllDifferences().size());
137
138 String dissimilarTest = "<clouds><cloud name=\"nimbus\"/></clouds>";
139 Diff dissimilarDiff = new Diff(control, dissimilarTest);
140 dissimilarDiff.overrideDifferenceListener(listener);
141 assertTrue("not similar " + dissimilarDiff.toString(),
142 !dissimilarDiff.similar());
143
144 DetailedDiff dissimilarDetailedDiff = new DetailedDiff(
145 new Diff(control, dissimilarTest));
146 dissimilarDetailedDiff.overrideDifferenceListener(listener);
147 List differences = dissimilarDetailedDiff.getAllDifferences();
148 assertEquals("wrong number of attributes, missing attribute, different attribute value, presence of subnodes, " +
149 "number of subnodes, missing text node. "
150 + dissimilarDetailedDiff.toString(),
151 6, differences.size());
152 int recoverable = 0;
153 for (Iterator iter = differences.iterator(); iter.hasNext(); ) {
154 Difference aDifference = (Difference) iter.next();
155 if (aDifference.isRecoverable()) {
156 recoverable++;
157 }
158 }
159 assertEquals("attribute value difference has been overridden as similar",
160 1, recoverable);
161 }
162
163 public void testIssue771839() throws Exception {
164 String xmlString1 = "<location>"
165 + "<street-address>22 any street</street-address>"
166 + "<postcode id='3'>XY0099Z</postcode>"
167 + "</location>";
168 String xmlString2 = "<location>"
169 + "<postcode1 id='1'>EC3M 1EB</postcode1>"
170 + "<street-address>20 east cheap</street-address>"
171 + "</location>";
172
173 Diff d = new Diff(xmlString1, xmlString2);
174 d.overrideDifferenceListener(listener);
175 assertFalse(d.similar());
176 assertTrue("postcode was matched against postcode1",
177 d.toString().indexOf("Expected element tag name 'postcode'"
178 + " but was 'postcode1'") > -1);
179 }
180
181 public void setUp() {
182 listener =
183 new IgnoreTextAndAttributeValuesDifferenceListener();
184 }
185
186 /**
187 * Constructor for test_IgnoreTextAndAttributeValuesDifferenceListener.
188 * @param name
189 */
190 public test_IgnoreTextAndAttributeValuesDifferenceListener(String name) {
191 super(name);
192 }
193 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileReader;
41
42 import org.xml.sax.InputSource;
43
44 import junit.framework.TestCase;
45
46 public class test_JAXP_1_2_Schema_Validation extends TestCase {
47
48 private Validator validator;
49
50 public void testUsingStringURI() throws Exception {
51 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
52 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
53 xsdFile.exists());
54
55 File xmlFile = new File(test_Constants.BASEDIR
56 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
57 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
58 xmlFile.exists());
59
60 validator = new Validator(new FileReader(xmlFile));
61
62 validator.useXMLSchema(true);
63 validator.setJAXP12SchemaSource(xsdFile.getAbsolutePath());
64
65 validator.assertIsValid();
66 }
67
68 public void testUsingInputStream() throws Exception {
69 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
70 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
71 xsdFile.exists());
72
73 File xmlFile = new File(test_Constants.BASEDIR
74 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
75 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
76 xmlFile.exists());
77
78 validator = new Validator(new FileReader(xmlFile));
79
80 validator.useXMLSchema(true);
81 validator.setJAXP12SchemaSource(new FileInputStream(xsdFile));
82
83 validator.assertIsValid();
84 }
85
86 public void testUsingInputSource() throws Exception {
87 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
88 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
89 xsdFile.exists());
90
91 File xmlFile = new File(test_Constants.BASEDIR
92 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
93 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
94 xmlFile.exists());
95
96 validator = new Validator(new FileReader(xmlFile));
97
98 validator.useXMLSchema(true);
99 validator
100 .setJAXP12SchemaSource(new InputSource(new FileReader(xsdFile)));
101
102 validator.assertIsValid();
103 }
104
105 public void testUsingAFile() throws Exception {
106 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
107 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
108 xsdFile.exists());
109
110 File xmlFile = new File(test_Constants.BASEDIR
111 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
112 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
113 xmlFile.exists());
114
115 validator = new Validator(new FileReader(xmlFile));
116
117 validator.useXMLSchema(true);
118 validator.setJAXP12SchemaSource(xsdFile);
119
120 validator.assertIsValid();
121 }
122
123 public void testUsingObjectArrayContainingStringURI() throws Exception {
124 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
125 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
126 xsdFile.exists());
127
128 File xmlFile = new File(test_Constants.BASEDIR
129 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
130 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
131 xmlFile.exists());
132
133 validator = new Validator(new FileReader(xmlFile));
134
135 validator.useXMLSchema(true);
136 validator.setJAXP12SchemaSource(new Object[] {
137 xsdFile.getAbsolutePath()
138 });
139
140 validator.assertIsValid();
141 }
142
143 public void testUsingNonExistentFile() throws Exception {
144 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/BookDoesNotExist.xsd");
145 assertFalse("xsdFile " + xsdFile.getAbsolutePath() + " exists",
146 xsdFile.exists());
147
148 File xmlFile = new File(test_Constants.BASEDIR
149 + "/tests/etc/BookXsdGeneratedNoSchema.xml");
150 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
151 xmlFile.exists());
152
153 validator = new Validator(new FileReader(xmlFile));
154
155 validator.useXMLSchema(true);
156 validator.setJAXP12SchemaSource(xsdFile);
157
158 assertFalse("Isn't valid since no schema can be found", validator.isValid());
159 }
160
161 public void testUsingInvalidXML() throws Exception {
162 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
163 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
164 xsdFile.exists());
165
166 File xmlFile = new File(test_Constants.BASEDIR
167 + "/tests/etc/InvalidBookXsdGeneratedNoSchema.xml");
168 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
169 xmlFile.exists());
170
171 validator = new Validator(new FileReader(xmlFile));
172
173 validator.useXMLSchema(true);
174 validator.setJAXP12SchemaSource(xsdFile);
175
176 assertFalse("Isn't valid since no schema can be found", validator.isValid());
177 }
178 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39
40 import junit.framework.TestCase;
41
42 import org.w3c.dom.Attr;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.Text;
47
48 /**
49 * JUnit test for NodeDescriptor
50 */
51 public class test_NodeDescriptor extends TestCase {
52 private StringBuffer stringBuffer;
53 private Document aDocument;
54 private NodeDetail nodeDetail;
55
56 public void testAppendDocumentDetail() throws Exception {
57 nodeDetail = new NodeDetail("", aDocument, "/");
58 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
59 assertEquals("<" + NodeDescriptor.DOCUMENT_NODE_DESCRIPTION
60 + "<...>> at /", stringBuffer.toString());
61 }
62
63 public void testAppendAttributeDetail() throws Exception {
64 String attrName = "attrName";
65 String attrValue = "attrValue";
66 Attr attr = aDocument.createAttribute(attrName);
67 attr.setValue(attrValue);
68 String tagName = "elemTag";
69 Element element = aDocument.createElement(tagName);
70 element.setAttributeNode(attr);
71 nodeDetail = new NodeDetail("", attr, "/elemTag");
72 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
73 assertEquals("<" + tagName + " "
74 + attrName + "=\"" + attrValue + "\"...> at /elemTag", stringBuffer.toString());
75 }
76
77 public void testAppendElementDetail() throws Exception {
78 String tagName = "elemTag";
79 Element element = aDocument.createElement(tagName);
80 nodeDetail = new NodeDetail("", element, "/elemTag");
81 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
82 assertEquals("<" + tagName + "...> at /elemTag", stringBuffer.toString());
83 }
84
85 public void testAppendTextDetail() throws Exception {
86 String textString = "some text";
87 Text text = aDocument.createTextNode(textString);
88 String tagName = "elemTag";
89 Element element = aDocument.createElement(tagName);
90 element.appendChild(text);
91 nodeDetail = new NodeDetail("", text, "/elemTag/text()");
92 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
93 assertEquals("<" + tagName + " ...>" + textString
94 + "</" + tagName + "> at /elemTag/text()", stringBuffer.toString());
95 }
96
97 public void testAppendProcessingInstructionDetail() throws Exception {
98 String target = "PItarget";
99 String data = "PIdata";
100 Node processingInstruction = aDocument.createProcessingInstruction(target, data);
101 nodeDetail = new NodeDetail("", processingInstruction, "/processing-instruction()");
102 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
103 assertEquals("<?" + target + " " + data + "?> at /processing-instruction()",
104 stringBuffer.toString());
105 }
106
107 public void testAppendCommentDetail() throws Exception {
108 String comments = "This is a comment";
109 Node comment = aDocument.createComment(comments);
110 nodeDetail = new NodeDetail("", comment, "/comment()");
111 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
112 assertEquals("<!--" + comments + "--> at /comment()", stringBuffer.toString());
113 }
114
115 public void testAppendCDataDetail() throws Exception {
116 String cData = "<>& etc";
117 Node cDataNote = aDocument.createCDATASection(cData);
118 nodeDetail = new NodeDetail("", cDataNote, "/text()");
119 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
120 assertEquals("<![CDATA[" + cData + "]]> at /text()", stringBuffer.toString());
121 }
122
123 public void testAppendDocTypeDetail() throws Exception {
124 File dtdA = File.createTempFile(getName() + "A", "dtd");
125 dtdA.deleteOnExit();
126 String systemOnlyDTD = "<!DOCTYPE blah SYSTEM \"" + dtdA.toURL().toExternalForm() + "\">";
127 String someContent = "<blah>ignored</blah>";
128 String xmlWithExternalDTD = systemOnlyDTD + someContent;
129
130 aDocument = XMLUnit.buildControlDocument(xmlWithExternalDTD);
131 Node doctypeA = aDocument.getDoctype();
132 nodeDetail = new NodeDetail("", doctypeA, "/");
133 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
134 assertEquals(systemOnlyDTD + " at /", stringBuffer.toString());
135
136 stringBuffer = new StringBuffer();
137 File dtdB = File.createTempFile(getName() + "B", "dtd");
138 dtdB.deleteOnExit();
139 String publicDTD = "<!DOCTYPE web-app "
140 + "PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN\" "
141 + "\"" + dtdB.toURL().toExternalForm() + "\">";
142 String someOtherContent = "<web-app><!--ignore me--></web-app>";
143 String xmlWithPublicDTD = publicDTD + someOtherContent;
144
145 Document bDocument = XMLUnit.buildControlDocument(xmlWithPublicDTD);
146 Node doctypeB = bDocument.getDoctype();
147 nodeDetail = new NodeDetail("", doctypeB, "/");
148 NodeDescriptor.appendNodeDetail(stringBuffer, nodeDetail);
149 assertEquals(publicDTD + " at /", stringBuffer.toString());
150 }
151
152 public void setUp() throws Exception {
153 aDocument = XMLUnit.newControlParser().newDocument();
154 stringBuffer = new StringBuffer();
155 }
156
157
158 /**
159 * Constructor for test_NodeDescriptor.
160 * @param name
161 */
162 public test_NodeDescriptor(String name) {
163 super(name);
164 }
165
166 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.InputStreamReader;
39 import java.io.StringReader;
40
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43
44 import org.w3c.dom.Document;
45
46 /**
47 * JUnit test for NodeInputStream
48 */
49 public class test_NodeInputStream extends TestCase {
50 private NodeInputStream nodeStream;
51 private final String frog = "";
52 private final String ribbit = "<frog><!-- eats slugs and snails -->"
53 + "<frogspawn>fertilised egg</frogspawn>"
54 + "<tadpole juvenile=\"true\"/></frog>";
55
56 public void setUp() throws Exception {
57 Document document = XMLUnit.buildControlDocument(ribbit);
58 nodeStream = new NodeInputStream(document);
59 }
60
61 public void testRead() throws Exception {
62 InputStreamReader reader = new InputStreamReader(nodeStream);
63
64 Diff diff = new Diff(new StringReader(ribbit), reader);
65 assertEquals(diff.toString(), true, diff.identical());
66 }
67
68 public void testAvailable() throws Exception {
69 int available = nodeStream.available();
70 assertEquals("available="+available, true, available > 0);
71
72 nodeStream.read();
73 assertEquals(available - 1, nodeStream.available());
74 }
75
76 public test_NodeInputStream(String name) {
77 super(name);
78 }
79
80 public static TestSuite suite() {
81 return new TestSuite(test_NodeInputStream.class);
82 }
83
84 }
85
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.StringReader;
39
40 import junit.framework.TestCase;
41 import junit.framework.TestSuite;
42
43 import org.w3c.dom.Node;
44
45 /**
46 * JUnit test for NodeTest
47 */
48 public class test_NodeTest extends TestCase {
49 private NodeTest nodeTest;
50
51 private class NodeTypeTester implements NodeTester {
52 private short type;
53 public NodeTypeTester(short type) {
54 this.type = type;
55 }
56 public void testNode(Node aNode, NodeTest forTest) {
57 assertEquals(type, aNode.getNodeType());
58 }
59 public void noMoreNodes(NodeTest forTest) {
60 }
61 }
62
63 private class RejectingNodeTester implements NodeTester {
64 public boolean completed;
65 public void testNode(Node aNode, NodeTest forTest)
66 throws NodeTestException {
67 throw new NodeTestException("Reject all nodes", aNode);
68 }
69 public void noMoreNodes(NodeTest forTest) throws NodeTestException {
70 completed = true;
71 throw new NodeTestException("Rejection");
72 }
73 }
74
75 public void testFiltering() throws Exception {
76 nodeTest = new NodeTest(
77 new StringReader("<message><hello>folks</hello></message>"));
78 short nodeType = Node.ELEMENT_NODE;
79 nodeTest.performTest(new NodeTypeTester(nodeType), nodeType);
80
81 nodeType = Node.TEXT_NODE;
82 nodeTest.performTest(new NodeTypeTester(nodeType), nodeType);
83
84 nodeType = Node.COMMENT_NODE;
85 nodeTest.performTest(new NodeTypeTester(nodeType), nodeType);
86
87 short[] nodeTypes = new short[] {Node.TEXT_NODE, Node.COMMENT_NODE};
88 nodeTest.performTest(new NodeTypeTester(Node.TEXT_NODE), nodeTypes);
89 }
90
91 public void testNodeTesting() throws Exception {
92 nodeTest = new NodeTest(
93 new StringReader("<keyboard><qwerty>standard</qwerty></keyboard>"));
94 RejectingNodeTester tester = new RejectingNodeTester();
95
96 try {
97 nodeTest.performTest(tester, Node.TEXT_NODE);
98 fail("Expected NodeTestException");
99 } catch (NodeTestException e) {
100 assertEquals("not completed", false, tester.completed);
101 }
102
103 try {
104 nodeTest.performTest(tester, Node.CDATA_SECTION_NODE);
105 fail("Expected NodeTestException");
106 } catch (NodeTestException e) {
107 assertEquals("completed", true, tester.completed);
108 }
109 }
110
111 public test_NodeTest(String name) {
112 super(name);
113 }
114
115 public static TestSuite suite() {
116 return new TestSuite(test_NodeTest.class);
117 }
118
119 }
120
0 /*
1 *****************************************************************
2 Copyright (c) 2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.HashMap;
39 import java.util.Map;
40 import junit.framework.Assert;
41 import junit.framework.TestCase;
42
43 public class test_QualifiedName extends TestCase {
44
45 public void testParseBareLocalName() {
46 Assert.assertEquals(new QualifiedName("foo"),
47 QualifiedName.valueOf("foo"));
48 }
49
50 public void testParseQNameToStringStyle() {
51 Assert.assertEquals(new QualifiedName("foo", "bar"),
52 QualifiedName.valueOf("{foo}bar"));
53 }
54
55 public void testParsePrefixStyle() {
56 Map m = new HashMap();
57 m.put("pre", "foo");
58 NamespaceContext ctx = new SimpleNamespaceContext(m);
59 Assert.assertEquals(new QualifiedName("foo", "bar"),
60 QualifiedName.valueOf("pre:bar", ctx));
61 }
62
63 public void testParsePrefixStyleImplicitContext() {
64 Map m = new HashMap();
65 m.put("pre", "foo");
66 XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(m));
67 try {
68 Assert.assertEquals(new QualifiedName("foo", "bar"),
69 QualifiedName.valueOf("pre:bar"));
70 } finally {
71 XMLUnit.setXpathNamespaceContext(null);
72 }
73 }
74
75 public void testValueMustNotBeNull() {
76 shouldThrowWithMessage(null, "null");
77 }
78
79 public void testLocalPartMustNotBeEmptyQNameStyle() {
80 shouldThrowWithMessage("{foo}", "must not be empty");
81 }
82
83 public void testLocalPartMustNotBeEmptyPrefixStyle() {
84 shouldThrowWithMessage("foo:", "must not be empty");
85 }
86
87 public void testPrefixStyleRequiresNamespaceContext() {
88 shouldThrowWithMessage("foo:bar", "without a NamespaceContext");
89 }
90
91 public void testPrefixMustBeKnownToContext() {
92 Map m = new HashMap();
93 XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(m));
94 try {
95 shouldThrowWithMessage("foo:bar", "foo is unknown");
96 } finally {
97 XMLUnit.setXpathNamespaceContext(null);
98 }
99 }
100
101 private void shouldThrowWithMessage(String valueToParse,
102 String messagePart) {
103 try {
104 QualifiedName.valueOf(valueToParse);
105 Assert.fail("expected IllegalArgumentException");
106 } catch (IllegalArgumentException ex) {
107 String msg = ex.getMessage();
108 Assert.assertTrue("exception message should contain '"
109 + messagePart + "' but was " + msg,
110 msg.indexOf(messagePart) >= 0);
111 }
112 }
113 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38
39 import junit.framework.TestCase;
40 import junit.framework.TestSuite;
41
42
43 /**
44 * JUnit test for Replacement
45 */
46 public class test_Replacement extends TestCase {
47 private Replacement replacement;
48
49 public void testCharReplacement() {
50 char[] ch = {'h','o','a','g'};
51 replacement = new Replacement(new char[] {'o','a'}, new char[] {'u'});
52 assertEquals("hug", new String(replacement.replace(ch)));
53
54 replacement = new Replacement(new char[] {'g'}, new char[] {'r', 's', 'e'});
55 assertEquals("hoarse", new String(replacement.replace(ch)));
56 assertEquals("hasReplaceBy", true, replacement.hasReplaceBy());
57 }
58
59 public void testSimpleString() {
60 replacement = new Replacement("x", "y");
61 // 1st char
62 assertEquals("yen", replacement.replace("xen"));
63 // last char
64 assertEquals("boy", replacement.replace("box"));
65 // not 1st or last
66 assertEquals("aye", replacement.replace("axe"));
67 // no replacement
68 assertEquals("bag", replacement.replace("bag"));
69 // multiple replacements
70 assertEquals("yoyo", replacement.replace("xoxo"));
71 // multiple concurrent replacements
72 assertEquals("yyjykyy", replacement.replace("xxjxkxx"));
73
74 assertEquals("hasReplaceBy", true, replacement.hasReplaceBy());
75 }
76
77 public void testComplexString() {
78 replacement = new Replacement(" a whole bunch of words",
79 "some other words altogether");
80 assertEquals("Here aresome other words altogether...",
81 replacement.replace("Here are a whole bunch of words..."));
82
83 replacement = new Replacement("pp", "p");
84 assertEquals("hapy", replacement.replace("happy"));
85 assertEquals("happy", replacement.replace("happppy"));
86 assertEquals("tap", replacement.replace("tapp"));
87 assertEquals("paw", replacement.replace("ppaw"));
88 }
89
90 public void testNullReplacebyString() {
91 replacement = new Replacement(" ", null);
92 assertEquals("hasReplaceBy", false, replacement.hasReplaceBy());
93 assertEquals("wedon'twantnowhitespace",
94 replacement.replace("we don't want no whitespace"));
95 }
96
97 public void testNullReplacebyChars() {
98 replacement = new Replacement(new char[] {'a'}, null);
99 assertEquals("hasReplaceBy", false, replacement.hasReplaceBy());
100 assertEquals("ntidisestblishmentrinism",
101 replacement.replace("antidisestablishmentarianism"));
102 }
103
104 public void testEmptyReplaceby() {
105 replacement = new Replacement(new char[] {'w'}, new char[0]);
106 assertEquals("hasReplaceBy", false, replacement.hasReplaceBy());
107 assertEquals("ibbleobble",
108 replacement.replace("wibblewobble"));
109 }
110
111 public test_Replacement(String name) {
112 super(name);
113 }
114
115 public static TestSuite suite() {
116 return new TestSuite(test_Replacement.class);
117 }
118
119 }
120
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import junit.framework.TestCase;
41
42 /**
43 * JUnit test for SimpleNamespaceContext
44 */
45 public class test_SimpleNamespaceContext extends TestCase {
46
47 private static final String[] PREFIXES = {"foo", "bar"};
48 private static final String URI = "urn:example";
49
50 public void testEmptyContextIsEmpty() {
51 assertFalse(SimpleNamespaceContext.EMPTY_CONTEXT.getPrefixes()
52 .hasNext());
53 }
54
55 public void testSimpleMap() {
56 validate(new SimpleNamespaceContext(setupMap()));
57 }
58
59 public void testCopyOfMap() {
60 HashMap map = setupMap();
61 SimpleNamespaceContext ctx = new SimpleNamespaceContext(map);
62 // change a mapping
63 map.put(PREFIXES[0], URI + PREFIXES[0]);
64 // add a new one
65 map.put(PREFIXES[0] + PREFIXES[0], URI);
66 validate(ctx);
67 }
68
69 private static HashMap setupMap() {
70 HashMap map = new HashMap();
71 for (int i = 0; i < PREFIXES.length; i++) {
72 map.put(PREFIXES[i], URI);
73 }
74 return map;
75 }
76
77 private static void validate(NamespaceContext ctx) {
78 for (int i = 0; i < PREFIXES.length; i++) {
79 assertEquals(URI, ctx.getNamespaceURI(PREFIXES[i]));
80 }
81 Iterator it = ctx.getPrefixes();
82 boolean[] found = new boolean[PREFIXES.length];
83 int count = 0;
84 while (it.hasNext()) {
85 count++;
86 String p = (String) it.next();
87 boolean foundThisPrefix = false;
88 for (int i = 0; !foundThisPrefix && i < PREFIXES.length; i++) {
89 if (PREFIXES[i].equals(p)) {
90 found[i] = foundThisPrefix = true;
91 }
92 }
93 if (!foundThisPrefix) {
94 fail("Prefix " + p + " should not be in this context");
95 }
96 }
97 assertEquals(PREFIXES.length, count);
98 for (int i = 0; i < PREFIXES.length; i++) {
99 assertTrue("Context contained " + PREFIXES[i], found[i]);
100 }
101 }
102 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import javax.xml.transform.OutputKeys;
39 import junit.framework.TestCase;
40 import junit.framework.TestSuite;
41
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.Text;
45
46 /**
47 * JUnit test for SimpleSerializer
48 */
49 public class test_SimpleSerializer extends TestCase {
50 private SimpleSerializer serializer ;
51
52 public void testNode() throws Exception {
53 String simpleXML = "<season><spring id=\"1\"><eg>daffodils</eg></spring></season>";
54 Document doc = XMLUnit.buildControlDocument(simpleXML);
55
56 serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
57 assertEquals(false, simpleXML.equals(serializer.serialize(doc)));
58
59 serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
60 assertEquals(simpleXML, serializer.serialize(doc));
61
62 Element testElem = doc.createElement("eg");
63 Text lamb = doc.createTextNode("lamb");
64 testElem.appendChild(lamb);
65
66 assertEquals("<eg>lamb</eg>", serializer.serialize(testElem));
67 }
68
69 public void setUp() {
70 serializer = new SimpleSerializer();
71 }
72
73 public test_SimpleSerializer(String name) {
74 super(name);
75 }
76
77 public static TestSuite suite() {
78 return new TestSuite(test_SimpleSerializer.class);
79 }
80
81 }
82
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import javax.xml.transform.OutputKeys;
39 import org.w3c.dom.Node;
40
41 /**
42 * JUnit test for SimpleXpathEngine
43 */
44 public class test_SimpleXpathEngine extends AbstractXpathEngineTests {
45
46 private SimpleXpathEngine simpleXpathEngine = new SimpleXpathEngine();
47
48 protected XpathEngine newXpathEngine() {
49 return simpleXpathEngine;
50 }
51
52 public void testGetXPathResultNode() throws Exception {
53 Node result = simpleXpathEngine.getXPathResultNode("test",
54 testDocument);
55 SimpleSerializer serializer = new SimpleSerializer();
56 serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
57 assertEquals(testString, serializer.serialize(result.getFirstChild()));
58 }
59
60 public void testGetMatchingNodesMatchText() throws Exception {
61 if (isJava5OrNewer()) {
62 // fails with "more recent" version of Xalan shipping with Java5
63 return;
64 }
65 super.testGetMatchingNodesMatchText();
66 }
67
68 public void testEvaluate() throws Exception {
69 if (isJava5OrNewer()) {
70 // fails with "more recent" version of Xalan shipping with Java5
71 return;
72 }
73 super.testEvaluate();
74 }
75
76 public test_SimpleXpathEngine(String name) {
77 super(name);
78 }
79
80 private static boolean isJava5OrNewer() {
81 try {
82 Class.forName("java.net.Proxy");
83 return true;
84 } catch (Exception e) {
85 return false;
86 }
87 }
88
89 }
90
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.StringReader;
39
40 import javax.xml.parsers.SAXParser;
41 import javax.xml.parsers.SAXParserFactory;
42 import junit.framework.TestSuite;
43
44 import org.w3c.dom.Document;
45 import org.xml.sax.InputSource;
46
47 /**
48 * JUnit test for TolerantSaxDocumentBuilder
49 */
50 public class test_TolerantSaxDocumentBuilder extends XMLTestCase {
51 private TolerantSaxDocumentBuilder builder;
52 private SAXParser parser;
53
54 private static final String SIMPLEST_XML = "<root><node>text</node></root>";
55
56 public void testSimpleDocument() throws Exception {
57 String simpleXML = XML_DECLARATION + SIMPLEST_XML;
58 Document simpleXMLDocument = XMLUnit.buildControlDocument(
59 simpleXML);
60 assertParsedDocumentEqual(simpleXMLDocument, simpleXML);
61 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") == -1);
62 }
63
64 private void assertParsedDocumentEqual(Document control, String test)
65 throws Exception {
66 InputSource parseSource = new InputSource(new StringReader(test));
67 parser.setProperty("http://xml.org/sax/properties/lexical-handler",
68 builder);
69 parser.parse(parseSource, builder);
70 assertXMLEqual(control, builder.getDocument());
71 }
72
73 public void testSimpleDocumentWithComments() throws Exception {
74 String xmlWithComments = XML_DECLARATION + "<more>" + SIMPLEST_XML
75 + "<!--this is a comment -->" + SIMPLEST_XML + "</more>";
76 Document documentWithComments = XMLUnit.buildControlDocument(
77 xmlWithComments);
78 assertParsedDocumentEqual(documentWithComments, xmlWithComments);
79 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") == -1);
80 }
81
82 public void testSimpleDocumentWithProcessingInstruction() throws Exception {
83 String xmlWithProcInstruction = XML_DECLARATION + "<more>" + SIMPLEST_XML
84 + "<?processing instruction?>" + SIMPLEST_XML + "</more>";
85 Document documentWithProcInstruction = XMLUnit.buildControlDocument(
86 xmlWithProcInstruction);
87 assertParsedDocumentEqual(documentWithProcInstruction,
88 xmlWithProcInstruction);
89 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") == -1);
90 }
91
92 public void testStartElementWithNoEnd() throws Exception {
93 builder.startDocument();
94 builder.startElement(null, null, "root", null);
95
96 Document oneElementDocument = XMLUnit.buildControlDocument("<root/>");
97 assertXMLEqual(oneElementDocument, builder.getDocument());
98 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") == -1);
99 }
100
101 public void testEndElementWithNoStart() throws Exception {
102 builder.startDocument();
103 builder.startElement(null, null, "root", null);
104 builder.endElement(null, null, "node");
105 builder.endElement(null, null, "root");
106
107 Document oneElementDocument = XMLUnit.buildControlDocument("<root/>");
108 assertXMLEqual(oneElementDocument, builder.getDocument());
109 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") != -1);
110 }
111
112 public void testEndElementBeforeStart() throws Exception {
113 builder.startDocument();
114 builder.endElement(null, null, "root");
115 builder.startElement(null, null, "root", null);
116
117 Document oneElementDocument = XMLUnit.buildControlDocument("<root/>");
118 assertXMLEqual(oneElementDocument, builder.getDocument());
119 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") != -1);
120 }
121
122 public void testTextBeforeStartElement() throws Exception {
123 String someText = "how could this happen?!";
124 builder.startDocument();
125 builder.characters(someText.toCharArray(), 0, someText.length());
126 builder.startElement(null, null, "root", null);
127
128 Document oneElementDocument = XMLUnit.buildControlDocument("<root/>");
129 assertXMLEqual(oneElementDocument, builder.getDocument());
130 assertTrue(builder.getTrace(), builder.getTrace().indexOf("WARNING") != -1);
131 }
132
133 public void setUp() throws Exception {
134 builder = new TolerantSaxDocumentBuilder(XMLUnit.newTestParser());
135 parser = SAXParserFactory.newInstance().newSAXParser();
136 }
137
138 public test_TolerantSaxDocumentBuilder(String name) {
139 super(name);
140 }
141
142 public static TestSuite suite() {
143 return new TestSuite(test_TolerantSaxDocumentBuilder.class);
144 }
145
146 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.File;
39 import java.io.FileReader;
40
41 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
42
43 import javax.xml.transform.OutputKeys;
44 import javax.xml.transform.Source;
45 import javax.xml.transform.URIResolver;
46 import junit.framework.TestCase;
47 import junit.framework.TestSuite;
48
49 import org.w3c.dom.Document;
50
51 /**
52 * Test a Transform
53 */
54 public class test_Transform extends TestCase{
55 private static final String FLEABALL = "<fleaball><animal><shaggy>dog</shaggy></animal></fleaball>";
56
57 private static final String DOG =
58 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dog/>" ;
59
60 private Transform transform;
61 private File animal;
62
63 public void testGetResultString() throws Exception {
64 transform = new Transform(FLEABALL, animal);
65 assertEquals(DOG, stripLineFeeds(transform.getResultString()));
66 }
67
68 public void testGetResultDocument() throws Exception {
69 transform = new Transform(FLEABALL, animal);
70 Diff diff = new Diff(DOG, transform);
71 assertEquals(diff.toString(), true, diff.identical());
72 }
73
74 public void testIdentityTransform() throws Exception {
75 Document control = XMLUnit.buildControlDocument(FLEABALL);
76 transform = new Transform(control);
77 Document test = transform.getResultDocument();
78 Diff diff = new Diff(control, test);
79 assertEquals(diff.toString(), true, diff.identical());
80 }
81
82 public void testOutputProperty() throws Exception {
83 transform = new Transform(FLEABALL, animal);
84 transform.setOutputProperty(OutputKeys.METHOD, "html");
85 assertNotEquals(DOG, transform.getResultString());
86 }
87
88 public void testDOMSourceAndFile() throws Exception {
89 transform = new Transform(XMLUnit.buildControlDocument(FLEABALL), animal);
90 assertEquals(DOG, stripLineFeeds(transform.getResultString()));
91 }
92
93 public void testDOMSourceAndString() throws Exception {
94 FileReader reader = new FileReader(animal);
95 try {
96 char[] animalXSL = new char[1024];
97 int length = reader.read(animalXSL);
98 transform = new Transform(XMLUnit.buildControlDocument(FLEABALL),
99 new String(animalXSL, 0, length));
100 assertEquals(DOG, stripLineFeeds(transform.getResultString()));
101 } finally {
102 reader.close();
103 }
104 }
105
106 /**
107 * Raised by Craig Strong 04.04.2002
108 */
109 public void testXSLIncludeWithoutSystemId() throws Exception {
110 String input = "<bug><animal>creepycrawly</animal></bug>";
111 String xslWithInclude = test_Constants.XML_DECLARATION
112 + test_Constants.XSLT_START
113 + test_Constants.XSLT_XML_OUTPUT_NOINDENT
114 + "<xsl:template match=\"bug\"><xsl:apply-templates select=\"animal\"/></xsl:template>"
115 + "<xsl:include href=\"" + test_Constants.BASEDIR + "/tests/etc/animal.xsl\"/>"
116 + test_Constants.XSLT_END;
117 Transform transform = new Transform(input, xslWithInclude);
118 transform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
119 assertEquals("<creepycrawly/>", transform.getResultString());
120 }
121
122 /**
123 * Issue 1742826
124 */
125 public void testURIResolverForStylesheet() throws Exception {
126 TestResolver tr = new TestResolver();
127 try {
128 XMLUnit.setURIResolver(tr);
129 String s = "<foo/>";
130 String xsl = test_Constants.XML_DECLARATION
131 + test_Constants.XSLT_START
132 + "<xsl:include href=\"urn:bar\"/>"
133 + test_Constants.XSLT_END;
134 try {
135 Transform transform = new Transform(s, xsl);
136 fail("should fail because of unknown include URI");
137 } catch (ConfigurationException tce) {
138 // expected exception
139 }
140 assertTrue("URIResolver has been called", tr.called);
141 } finally {
142 XMLUnit.setURIResolver(null);
143 }
144 }
145
146 private void assertNotEquals(Object expected, Object actual) {
147 if (expected.equals(actual)) {
148 fail("Expected " + expected + " different to actual!");
149 }
150 }
151
152 public test_Transform(String name) {
153 super(name);
154 }
155
156 public void setUp() throws Exception {
157 animal = new File(test_Constants.BASEDIR + "/tests/etc/animal.xsl");
158 }
159
160 private static String stripLineFeeds(String s) {
161 int index = s.indexOf(test_Constants.LINE_SEPARATOR);
162 while (index > -1) {
163 s = s.substring(0, index)
164 + s.substring(index + test_Constants.LINE_SEPARATOR.length()) ;
165 index = s.indexOf(test_Constants.LINE_SEPARATOR);
166 }
167 return s;
168 }
169
170 private static class TestResolver implements URIResolver {
171 private boolean called = false;
172
173 public Source resolve(String h, String b) {
174 called = true;
175 return null;
176 }
177 }
178 }
179
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import junit.framework.AssertionFailedError;
39 import junit.framework.TestSuite;
40 import org.w3c.dom.Document;
41 import org.xml.sax.InputSource;
42
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.FileReader;
46 import java.io.FileWriter;
47 import java.io.StringBufferInputStream;
48 import java.io.StringReader;
49
50 /**
51 * JUnit test for Validator
52 * Also includes tests for XMLTestCase <code>assertValidXML</code> methods
53 * because test values etc are here
54 */
55 public class test_Validator extends XMLTestCase {
56 private Validator validator;
57 private File tempDTDFile;
58
59 public void testXSchema() throws Exception{
60 File xsdFile = new File(test_Constants.BASEDIR + "/tests/etc/Book.xsd");
61 assertTrue("xsdFile " + xsdFile.getAbsolutePath() + " exists",
62 xsdFile.exists());
63
64 File xmlFile = new File(test_Constants.BASEDIR
65 + "/tests/etc/BookXsdGenerated.xml");
66 assertTrue("xmlFile " + xmlFile.getAbsolutePath() + " exists",
67 xmlFile.exists());
68 validator =
69 new Validator(new InputSource(new FileInputStream(xmlFile)));
70
71 validator.useXMLSchema(true);
72 assertTrue("Schema " + validator.toString(), validator.isValid());
73 }
74
75 public void testIsValidGood() throws Exception {
76 String toonXML = test_Constants.XML_DECLARATION
77 + test_Constants.CHUCK_JONES_RIP_DTD_DECL
78 + test_Constants.CHUCK_JONES_RIP_XML;
79 validator = new Validator(new StringReader(toonXML));
80 assertTrue("toonXML " + validator.toString(), validator.isValid());
81 // test XMLTestCase
82 passXMLTestCaseTest(toonXML);
83 passXMLTestCaseTest(validator);
84
85 String noXMLDeclaration = test_Constants.CHUCK_JONES_RIP_DTD_DECL
86 + test_Constants.CHUCK_JONES_RIP_XML;
87 validator = new Validator(new StringReader(noXMLDeclaration));
88 assertEquals("noXMLDeclaration " + validator.toString(),
89 true, validator.isValid());
90 // test XMLTestCase
91 passXMLTestCaseTest(noXMLDeclaration);
92 passXMLTestCaseTest(validator);
93 }
94
95 public void testIsValidExternalSystemId() throws Exception {
96 writeTempDTDFile();
97 assertTrue(tempDTDFile.getAbsolutePath(), tempDTDFile.exists());
98
99 String externalDTD = test_Constants.XML_DECLARATION
100 + test_Constants.DOCUMENT_WITH_GOOD_EXTERNAL_DTD;
101 String tempDTDUrl = tempDTDFile.toURL().toExternalForm();
102 validator = new Validator(new StringReader(externalDTD),
103 tempDTDUrl);
104
105 assertTrue("externalDTD " + validator.toString(), validator.isValid());
106 // test XMLTestCase
107 passXMLTestCaseTest(externalDTD, tempDTDFile.toURL().toExternalForm());
108 passXMLTestCaseTest(validator);
109
110 String noDTD = test_Constants.XML_DECLARATION
111 + test_Constants.DOCUMENT_WITH_NO_EXTERNAL_DTD;
112 validator = new Validator(new StringReader(noDTD),
113 tempDTDFile.toURL().toExternalForm());
114
115 assertFalse("noDTD " + validator.toString(), validator.isValid());
116 // test XMLTestCase
117 failXMLTestCaseTest(noDTD, tempDTDFile.toURL().toExternalForm());
118 failXMLTestCaseTest(validator);
119 }
120
121 public void testIsValidNoDTD() throws Exception {
122 writeTempDTDFile();
123 assertTrue(tempDTDFile.getAbsolutePath(), tempDTDFile.exists());
124
125 String noDTD = test_Constants.CHUCK_JONES_RIP_XML;
126 String systemid = tempDTDFile.toURL().toExternalForm();
127 String doctype = "cartoons";
128 String notDoctype = "anima";
129 validator = new Validator(new StringReader(noDTD),
130 systemid, doctype);
131 assertTrue(validator.toString(), validator.isValid());
132 // test XMLTestCase
133 passXMLTestCaseTest(noDTD, systemid, doctype);
134 passXMLTestCaseTest(validator);
135 // and Document constructor
136 Document document = getDocument(noDTD);
137 validator = new Validator(document, systemid, doctype);
138 assertTrue("Document " + validator.toString(), validator.isValid());
139
140 validator = new Validator(new StringReader(noDTD),
141 systemid, notDoctype);
142 assertFalse(validator.toString(), validator.isValid());
143 // test XMLTestCase
144 failXMLTestCaseTest(noDTD, systemid, notDoctype);
145 failXMLTestCaseTest(validator);
146 // and Document constructor
147 validator = new Validator(document, systemid, notDoctype);
148 assertFalse("Document " + validator.toString(), validator.isValid());
149 }
150
151 public void testIsValidBad() throws Exception {
152 String noDTD = test_Constants.XML_DECLARATION
153 + test_Constants.CHUCK_JONES_RIP_XML;
154 validator = new Validator(new StringReader(noDTD));
155 assertFalse("noDTD " + validator.toString(), validator.isValid());
156 // test XMLTestCase
157 failXMLTestCaseTest(noDTD);
158 failXMLTestCaseTest(validator);
159
160 String dtdTwice = test_Constants.XML_DECLARATION
161 + test_Constants.CHUCK_JONES_RIP_DTD_DECL
162 + test_Constants.CHUCK_JONES_RIP_DTD_DECL
163 + test_Constants.CHUCK_JONES_RIP_XML;
164 validator = new Validator(new StringReader(dtdTwice));
165 assertFalse("dtdTwice " + validator.toString(), validator.isValid());
166 // test XMLTestCase
167 failXMLTestCaseTest(dtdTwice);
168 failXMLTestCaseTest(validator);
169
170 String invalidXML = test_Constants.XML_DECLARATION
171 + test_Constants.CHUCK_JONES_RIP_DTD_DECL
172 + test_Constants.CHUCK_JONES_SPINNING_IN_HIS_GRAVE_XML;
173 validator = new Validator(new StringReader(invalidXML));
174 assertFalse("invalidXML " + validator.toString(), validator.isValid());
175 // test XMLTestCase
176 failXMLTestCaseTest(invalidXML);
177 failXMLTestCaseTest(validator);
178 }
179
180 private Document getDocument(String fromXML) throws Exception {
181 return XMLUnit.buildControlDocument(fromXML);
182 }
183
184 private void removeTempDTDFile() throws Exception {
185 if (tempDTDFile.exists()) {
186 tempDTDFile.delete();
187 }
188 }
189
190 private void writeTempDTDFile() throws Exception {
191 FileWriter writer = new FileWriter(tempDTDFile);
192 writer.write(test_Constants.CHUCK_JONES_RIP_DTD);
193 writer.close();
194 }
195
196 public void setUp() throws Exception {
197 tempDTDFile = new File(test_Constants.EXTERNAL_DTD);
198 removeTempDTDFile();
199 }
200
201 public void tearDown() throws Exception {
202 removeTempDTDFile();
203 }
204
205 // ---- XMLTestCase methods ----
206 private void passXMLTestCaseTest(String xml) throws Exception {
207 assertXMLValid(xml);
208 assertXMLValid(new InputSource(new StringReader(xml)));
209 assertXMLValid(new InputSource(new StringBufferInputStream(xml)));
210 }
211 private void passXMLTestCaseTest(String xml, String systemId) throws Exception {
212 assertXMLValid(xml, systemId);
213 assertXMLValid(new InputSource(new StringReader(xml)), systemId);
214 assertXMLValid(new InputSource(new StringBufferInputStream(xml)),
215 systemId);
216 }
217 private void passXMLTestCaseTest(String xml, String systemId, String doctype)
218 throws Exception {
219 assertXMLValid(xml, systemId, doctype);
220 assertXMLValid(new InputSource(new StringReader(xml)), systemId,
221 doctype);
222 assertXMLValid(new InputSource(new StringBufferInputStream(xml)),
223 systemId, doctype);
224 }
225 private void passXMLTestCaseTest(Validator validator) throws Exception {
226 assertXMLValid(validator);
227 }
228 private void failXMLTestCaseTest(String xml, String systemId) throws Exception {
229 try {
230 assertXMLValid(xml, systemId);
231 fail("Expected assertion to fail!");
232 } catch (AssertionFailedError e) {
233 // expecting this
234 }
235 try {
236 assertXMLValid(new InputSource(new StringReader(xml)), systemId);
237 fail("Expected assertion to fail!");
238 } catch (AssertionFailedError e) {
239 // expecting this
240 }
241 try {
242 assertXMLValid(new InputSource(new StringBufferInputStream(xml)),
243 systemId);
244 fail("Expected assertion to fail!");
245 } catch (AssertionFailedError e) {
246 // expecting this
247 }
248 }
249 private void failXMLTestCaseTest(String xml) throws Exception {
250 try {
251 assertXMLValid(xml);
252 fail("Expected assertion to fail!");
253 } catch (AssertionFailedError e) {
254 // expecting this
255 }
256 try {
257 assertXMLValid(new InputSource(new StringReader(xml)));
258 fail("Expected assertion to fail!");
259 } catch (AssertionFailedError e) {
260 // expecting this
261 }
262 try {
263 assertXMLValid(new InputSource(new StringBufferInputStream(xml)));
264 fail("Expected assertion to fail!");
265 } catch (AssertionFailedError e) {
266 // expecting this
267 }
268 }
269 private void failXMLTestCaseTest(String xml, String systemId, String doctype)
270 throws Exception {
271 try {
272 assertXMLValid(xml, systemId, doctype);
273 fail("Expected assertion to fail!");
274 } catch (AssertionFailedError e) {
275 // expecting this
276 }
277 try {
278 assertXMLValid(new InputSource(new StringReader(xml)), systemId,
279 doctype);
280 fail("Expected assertion to fail!");
281 } catch (AssertionFailedError e) {
282 // expecting this
283 }
284 try {
285 assertXMLValid(new InputSource(new StringBufferInputStream(xml)),
286 systemId, doctype);
287 fail("Expected assertion to fail!");
288 } catch (AssertionFailedError e) {
289 // expecting this
290 }
291 }
292 private void failXMLTestCaseTest(Validator validator) throws Exception {
293 try {
294 assertXMLValid(validator);
295 fail("Expected assertion to fail!");
296 } catch (AssertionFailedError e) {
297 // expecting this
298 }
299 }
300
301 public test_Validator(String name) {
302 super(name);
303 }
304
305 public static TestSuite suite() {
306 return new TestSuite(test_Validator.class);
307 }
308
309 }
310
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2011,2014 Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import java.io.FileNotFoundException;
39 import java.io.FileReader;
40 import java.io.StringReader;
41 import java.util.HashMap;
42 import java.util.Map;
43
44 import junit.framework.AssertionFailedError;
45 import junit.framework.TestSuite;
46
47 import org.w3c.dom.Document;
48 import org.w3c.dom.Node;
49
50 /**
51 * Test case used to test the XMLTestCase
52 */
53 public class test_XMLTestCase extends XMLTestCase {
54 private static final String PREFIX = "foo";
55 private static final String TEST_NS = "urn:org.example";
56 private static final NamespaceContext NS_CONTEXT;
57 static {
58 HashMap m = new HashMap();
59 m.put(PREFIX, TEST_NS);
60 NS_CONTEXT = new SimpleNamespaceContext(m);
61 }
62
63 private final String[] control = new String[]{
64 "<root/>",
65 "<root></root>",
66 "<root>test</root>",
67 "<root attr=\"test\">test</root>",
68 "<test/>",
69 "<root>test</root>",
70 "<root attr=\"test\"/>",
71 "<root><outer><inner></inner></outer></root>",
72 "<root attr=\"test\"><outer>test<inner>test</inner></outer></root>",
73 "<root attr=\"test\"><outer>test<inner>test</inner></outer></root>"
74 };
75 private final String[] test = new String[]{
76 "<fail/>",
77 "<fail/>",
78 "<fail>test</fail>",
79 "<root>test</root>",
80 "<fail/>",
81 "<root>fail</root>",
82 "<root attr=\"fail\"/>",
83 "<root><outer><inner>test</inner></outer></root>",
84 "<root attr=\"test\"><outer>fail<inner>test</inner></outer></root>",
85 "<root attr=\"fail\"><outer>test<inner>test</inner></outer></root>"
86 };
87
88 /**
89 * Test for the compareXML method.
90 */
91 public void testCompareXMLStrings() throws Exception {
92 for(int i=0;i<control.length;i++){
93 assertEquals("compareXML case " + i + " failed", true,
94 compareXML(control[i], control[i]).similar());
95 assertEquals("!compareXML case " + i + " failed", false,
96 compareXML(control[i], test[i]).similar());
97 }
98 }
99
100 /**
101 * Test the comparision of two files
102 */
103 public void testXMLEqualsFiles() throws Exception {
104 assertXMLEqual(new FileReader(
105 test_Constants.BASEDIR + "/tests/etc/test1.xml"),
106 new FileReader(
107 test_Constants.BASEDIR + "/tests/etc/test1.xml"));
108 assertXMLNotEqual(new FileReader(
109 test_Constants.BASEDIR + "/tests/etc/test1.xml"),
110 new FileReader(
111 test_Constants.BASEDIR + "/tests/etc/test2.xml"));
112
113 // Bug 956372
114 assertXMLEqual("equal message", new FileReader(
115 test_Constants.BASEDIR + "/tests/etc/test1.xml"),
116 new FileReader(
117 test_Constants.BASEDIR + "/tests/etc/test1.xml"));
118 assertXMLNotEqual("notEqual message", new FileReader(
119 test_Constants.BASEDIR + "/tests/etc/test1.xml"),
120 new FileReader(
121 test_Constants.BASEDIR + "/tests/etc/test2.xml"));
122
123 try{
124 assertXMLNotEqual(new FileReader("nosuchfile.xml"),
125 new FileReader("nosuchfile.xml"));
126 fail("Expecting FileNotFoundException");
127 }catch(FileNotFoundException e){}
128 }
129
130 /**
131 * Test for the assertXMLEquals method.
132 */
133 public void testXMLEqualsStrings() throws Exception {
134 for(int i=0;i<control.length;i++){
135 assertXMLEqual("assertXMLEquals test case " + i + " failed",
136 control[i], control[i]);
137 assertXMLNotEqual("assertXMLNotEquals test case" + i + " failed",
138 control[i], test[i]);
139 }
140 }
141
142 /**
143 * Test for the assertXMLEquals method.
144 */
145 public void testXMLEqualsDocuments() throws Exception {
146 Document controlDocument, testDocument;
147 for(int i=0;i<control.length;i++){
148 controlDocument = XMLUnit.buildControlDocument(control[i]);
149 assertXMLEqual("assertXMLEquals test case " + i + " failed",
150 controlDocument, controlDocument);
151 testDocument = XMLUnit.buildTestDocument(test[i]);
152 assertXMLNotEqual("assertXMLNotEquals test case" + i + " failed",
153 controlDocument, testDocument);
154 }
155 }
156
157 private static final String xpathValuesControlXML =
158 "<root><outer attr=\"urk\"><inner attr=\"urk\">"
159 + "controlDocument</inner></outer></root>";
160 private static final String xpathValuesTestXML =
161 "<root><outer attr=\"urk\"><inner attr=\"ugh\">"
162 + "testDocument</inner></outer></root>";
163 private static final String xpathValuesControlXMLNS =
164 addNamespaceToDocument(xpathValuesControlXML);
165 private static final String xpathValuesTestXMLNS =
166 addNamespaceToDocument(xpathValuesTestXML);
167
168 public void testXpathValuesEqualUsingDocument() throws Exception {
169 Document controlDocument = XMLUnit.buildControlDocument(xpathValuesControlXML);
170 Document testDocument = XMLUnit.buildTestDocument(xpathValuesTestXML);
171
172 assertXpathValuesEqual("//text()", "//inner/text()", controlDocument);
173 assertXpathValuesEqual("//inner/@attr", controlDocument,
174 "//outer/@attr", testDocument);
175
176 assertXpathValuesNotEqual("//inner/text()", "//outer/@attr", controlDocument);
177 assertXpathValuesNotEqual("//inner/text()", controlDocument,
178 "//text()", testDocument);
179 }
180
181 public void testXpathValuesEqualUsingDocumentNS() throws Exception {
182 Document controlDocument = XMLUnit.buildControlDocument(xpathValuesControlXMLNS);
183 Document testDocument = XMLUnit.buildTestDocument(xpathValuesTestXMLNS);
184
185 assertXpathValuesNotEqual("//text()",
186 "//inner/text()", controlDocument);
187 XMLUnit.setXpathNamespaceContext(NS_CONTEXT);
188 assertXpathValuesEqual("//text()",
189 "//" + PREFIX + ":inner/text()",
190 controlDocument);
191 assertXpathValuesEqual("//" + PREFIX + ":inner/@attr", controlDocument,
192 "//" + PREFIX + ":outer/@attr", testDocument);
193
194 assertXpathValuesNotEqual("//" + PREFIX + ":inner/text()",
195 "//" + PREFIX + ":outer/@attr",
196 controlDocument);
197 assertXpathValuesNotEqual("//" + PREFIX + ":inner/text()",
198 controlDocument,
199 "//text()",
200 testDocument);
201 }
202
203 public void testXpathValuesEqualUsingString() throws Exception {
204 assertXpathValuesEqual("//text()", "//inner/text()", xpathValuesControlXML);
205 assertXpathValuesEqual("//inner/@attr", xpathValuesControlXML,
206 "//outer/@attr", xpathValuesTestXML);
207
208 assertXpathValuesNotEqual("//inner/text()", "//outer/@attr", xpathValuesControlXML);
209 assertXpathValuesNotEqual("//inner/text()", xpathValuesControlXML,
210 "//text()", xpathValuesTestXML);
211 }
212
213 public void testXpathValuesEqualUsingStringNS() throws Exception {
214 assertXpathValuesNotEqual("//text()", "//inner/text()",
215 xpathValuesControlXMLNS);
216 XMLUnit.setXpathNamespaceContext(NS_CONTEXT);
217 assertXpathValuesEqual("//text()",
218 "//" + PREFIX + ":inner/text()",
219 xpathValuesControlXMLNS);
220 assertXpathValuesEqual("//" + PREFIX + ":inner/@attr",
221 xpathValuesControlXMLNS,
222 "//" + PREFIX + ":outer/@attr",
223 xpathValuesTestXMLNS);
224
225 assertXpathValuesNotEqual("//" + PREFIX + ":inner/text()",
226 "//" + PREFIX + ":outer/@attr",
227 xpathValuesControlXMLNS);
228 assertXpathValuesNotEqual("//" + PREFIX + ":inner/text()",
229 xpathValuesControlXMLNS,
230 "//text()", xpathValuesTestXMLNS);
231 }
232
233 public void testXpathEvaluatesTo() throws Exception {
234 assertXpathEvaluatesTo("urk", "//outer/@attr", xpathValuesControlXML);
235 try {
236 assertXpathEvaluatesTo("yum", "//inner/@attr", xpathValuesControlXML);
237 fail("Expected assertion to fail #1");
238 } catch (AssertionFailedError e) {
239 }
240 assertXpathEvaluatesTo("2", "count(//@attr)", xpathValuesControlXML);
241
242 Document testDocument = XMLUnit.buildTestDocument(xpathValuesTestXML);
243 assertXpathEvaluatesTo("ugh", "//inner/@attr", testDocument);
244 try {
245 assertXpathEvaluatesTo("yeah", "//outer/@attr", testDocument);
246 fail("Expected assertion to fail #2");
247 } catch (AssertionFailedError e) {
248 }
249
250 }
251
252 public void testXpathEvaluatesToNS() throws Exception {
253 try {
254 assertXpathEvaluatesTo("urk", "//outer/@attr",
255 xpathValuesControlXMLNS);
256 fail("Expected assertion to fail #1");
257 } catch (AssertionFailedError e) {
258 }
259
260 XMLUnit.setXpathNamespaceContext(NS_CONTEXT);
261 assertXpathEvaluatesTo("urk", "//" + PREFIX + ":outer/@attr",
262 xpathValuesControlXMLNS);
263 try {
264 assertXpathEvaluatesTo("yum", "//" + PREFIX + ":inner/@attr",
265 xpathValuesControlXMLNS);
266 fail("Expected assertion to fail #2");
267 } catch (AssertionFailedError e) {
268 }
269 assertXpathEvaluatesTo("2", "count(//@attr)", xpathValuesControlXMLNS);
270
271 Document testDocument = XMLUnit.buildTestDocument(xpathValuesTestXMLNS);
272 assertXpathEvaluatesTo("ugh", "//" + PREFIX + ":inner/@attr",
273 testDocument);
274 try {
275 assertXpathEvaluatesTo("yeah", "//" + PREFIX + ":outer/@attr",
276 testDocument);
277 fail("Expected assertion to fail #3");
278 } catch (AssertionFailedError e) {
279 }
280
281 }
282
283 public void testNodeTest() throws Exception {
284 NodeTester tester = new CountingNodeTester(1);
285 assertNodeTestPasses(xpathValuesControlXML, tester, Node.TEXT_NODE);
286 try {
287 assertNodeTestPasses(xpathValuesControlXML, tester, Node.ELEMENT_NODE);
288 fail("Expected node test failure #1!");
289 } catch (AssertionFailedError e) {
290 }
291
292 NodeTest test = new NodeTest(new StringReader(xpathValuesTestXML));
293 tester = new CountingNodeTester(4);
294 assertNodeTestPasses(test, tester,
295 new short[] {Node.TEXT_NODE, Node.ELEMENT_NODE}, true);
296 assertNodeTestPasses(test, tester,
297 new short[] {Node.TEXT_NODE, Node.COMMENT_NODE}, false);
298
299 try {
300 assertNodeTestPasses(test, tester,
301 new short[] {Node.TEXT_NODE, Node.ELEMENT_NODE}, false);
302 fail("Expected node test failure #2!");
303 assertNodeTestPasses(test, tester,
304 new short[] {Node.TEXT_NODE, Node.COMMENT_NODE}, true);
305 fail("Expected node test failure #3!");
306 } catch (AssertionFailedError e) {
307 }
308 }
309
310 public void testXMLValid() {
311 // see test_Validator class
312 }
313
314 private static final String TREES_OPEN = "<trees>";
315 private static final String TREES_CLOSE = "</trees>";
316 private static final String xpathNodesControlXML = TREES_OPEN
317 + "<tree evergreen=\"false\">oak</tree>"
318 + "<tree evergreen=\"false\">ash</tree>"
319 + "<tree evergreen=\"true\">scots pine</tree>"
320 + "<tree evergreen=\"true\">spruce</tree>"
321 + "<favourite><!-- is this a tree or a bush?! -->"
322 + "<tree evergreen=\"false\">magnolia</tree>"
323 + "</favourite>"
324 + "<fruit>"
325 + "<apples><crunchy/><yum/><tree evergreen=\"false\">apple</tree></apples>"
326 + "</fruit>"
327 + TREES_CLOSE;
328 private static final String xpathNodesTestXML = TREES_OPEN
329 + "<tree evergreen=\"false\">oak</tree>"
330 + "<tree evergreen=\"false\">ash</tree>"
331 + "<tree evergreen=\"true\">scots pine</tree>"
332 + "<tree evergreen=\"true\">spruce</tree>"
333 + "<tree flowering=\"true\">cherry</tree>"
334 + "<tree flowering=\"true\">apple</tree>"
335 + "<favourite><!-- is this a tree or a bush?! -->"
336 + "<tree evergreen=\"false\">magnolia</tree>"
337 + "</favourite>"
338 + "<apples><crunchy/><yum/><tree evergreen=\"false\">apple</tree></apples>"
339 + TREES_CLOSE;
340
341 public void testXpathsEqual() throws Exception {
342 Document controlDoc = XMLUnit.buildControlDocument(xpathNodesControlXML);
343 Document testDoc = XMLUnit.buildTestDocument(xpathNodesTestXML);
344
345 String[] controlXpath = new String[]{"/trees/tree[@evergreen]",
346 "//tree[@evergreen='false']",
347 "/trees/favourite",
348 "//fruit/apples"};
349 String[] testXpath = {controlXpath[0],
350 controlXpath[1],
351 "//favourite",
352 "//apples"};
353
354 // test positive passes
355 for (int i=0; i < controlXpath.length; ++i) {
356 assertXpathsEqual(controlXpath[i], controlDoc,
357 testXpath[i], testDoc);
358 assertXpathsEqual(controlXpath[i], xpathNodesControlXML,
359 testXpath[i], xpathNodesTestXML);
360 assertXpathsEqual(controlXpath[i], testXpath[i], controlDoc);
361 assertXpathsEqual(controlXpath[i], testXpath[i], xpathNodesControlXML);
362 }
363 // test negative fails
364 for (int i=0; i < controlXpath.length; ++i) {
365 try {
366 assertXpathsNotEqual(controlXpath[i], controlDoc,
367 testXpath[i], testDoc);
368 fail("should not be notEqual!");
369 } catch (AssertionFailedError e) {
370 }
371 try {
372 assertXpathsNotEqual(controlXpath[i], xpathNodesControlXML,
373 testXpath[i], xpathNodesTestXML);
374 fail("should not be notEqual!");
375 } catch (AssertionFailedError e) {
376 }
377 try {
378 assertXpathsNotEqual(controlXpath[i], testXpath[i], controlDoc);
379 fail("should not be notEqual!");
380 } catch (AssertionFailedError e) {
381 }
382 try {
383 assertXpathsNotEqual(controlXpath[i], testXpath[i], xpathNodesControlXML);
384 fail("should not be notEqual!");
385 } catch (AssertionFailedError e) {
386 }
387 }
388 }
389
390 public void testXpathsNotEqual() throws Exception {
391 Document controlDoc = XMLUnit.buildControlDocument(xpathNodesControlXML);
392 Document testDoc = XMLUnit.buildTestDocument(xpathNodesTestXML);
393
394 String[] controlXpath = new String[]{"/trees/tree[@evergreen]",
395 "//tree[@evergreen='false']",
396 "/trees/favourite",
397 "//fruit/apples"};
398 String[] testXpath = {"//tree",
399 "//tree[@evergreen='true']",
400 "//favourite/apples",
401 "//apples/tree"};
402
403 // test positive passes
404 for (int i=0; i < controlXpath.length; ++i) {
405 assertXpathsNotEqual(controlXpath[i], controlDoc,
406 testXpath[i], testDoc);
407 assertXpathsNotEqual(controlXpath[i], xpathNodesControlXML,
408 testXpath[i], xpathNodesTestXML);
409 assertXpathsNotEqual(controlXpath[i], testXpath[i], controlDoc);
410 assertXpathsNotEqual(controlXpath[i], testXpath[i], xpathNodesControlXML);
411 }
412 // test negative fails
413 for (int i=0; i < controlXpath.length; ++i) {
414 try {
415 assertXpathsEqual(controlXpath[i], controlDoc,
416 testXpath[i], testDoc);
417 fail("should not be Equal!");
418 } catch (AssertionFailedError e) {
419 }
420 try {
421 assertXpathsEqual(controlXpath[i], xpathNodesControlXML,
422 testXpath[i], xpathNodesTestXML);
423 fail("should not be Equal!");
424 } catch (AssertionFailedError e) {
425 }
426 try {
427 assertXpathsEqual(controlXpath[i], testXpath[i], controlDoc);
428 fail("should not be Equal!");
429 } catch (AssertionFailedError e) {
430 }
431 try {
432 assertXpathsEqual(controlXpath[i], testXpath[i], xpathNodesControlXML);
433 fail("should not be Equal!");
434 } catch (AssertionFailedError e) {
435 }
436 }
437 }
438
439 public void testDocumentAssertXpathExists() throws Exception {
440 Document controlDoc = XMLUnit.buildControlDocument(xpathNodesControlXML);
441 assertXpathExists("/trees/fruit/apples/yum", controlDoc);
442 assertXpathExists("//tree[@evergreen='false']", controlDoc);
443 try {
444 assertXpathExists("//tree[@evergreen='idunno']", controlDoc);
445 fail("Xpath does not exist");
446 } catch (AssertionFailedError e) {
447 // expected
448 }
449 }
450
451 public void testStringAssertXpathExists() throws Exception {
452 assertXpathExists("/trees/fruit/apples/yum", xpathNodesControlXML);
453 assertXpathExists("//tree[@evergreen='false']", xpathNodesControlXML);
454 try {
455 assertXpathExists("//tree[@evergreen='idunno']", xpathNodesControlXML);
456 fail("Xpath does not exist");
457 } catch (AssertionFailedError e) {
458 // expected
459 }
460 }
461
462 public void testDocumentAssertNotXpathExists() throws Exception {
463 Document controlDoc = XMLUnit.buildControlDocument(xpathNodesControlXML);
464 assertXpathNotExists("//tree[@evergreen='idunno']", controlDoc);
465 try {
466 assertXpathNotExists("/trees/fruit/apples/yum", controlDoc);
467 fail("Xpath does exist, once");
468 } catch (AssertionFailedError e) {
469 // expected
470 }
471 try {
472 assertXpathNotExists("//tree[@evergreen='false']", controlDoc);
473 fail("Xpath does exist many times");
474 } catch (AssertionFailedError e) {
475 // expected
476 }
477 }
478
479 public void testStringAssertNotXpathExists() throws Exception {
480 assertXpathNotExists("//tree[@evergreen='idunno']", xpathNodesControlXML);
481 try {
482 assertXpathNotExists("/trees/fruit/apples/yum", xpathNodesControlXML);
483 fail("Xpath does exist, once");
484 } catch (AssertionFailedError e) {
485 // expected
486 }
487 try {
488 assertXpathNotExists("//tree[@evergreen='false']", xpathNodesControlXML);
489 fail("Xpath does exist many times");
490 } catch (AssertionFailedError e) {
491 // expected
492 }
493 }
494
495 // Bug 585555
496 public void testUnusedNamespacesDontMatter() throws Exception
497 {
498 boolean startValueIgnoreWhitespace = XMLUnit.getIgnoreWhitespace();
499 try {
500 XMLUnit.setIgnoreWhitespace(true);
501 String a = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
502 "<outer xmlns:NS2=\"http://namespace2/foo\">\n" +
503 " <inner xmlns:NS2=\"http://namespace2/\">5</inner>\n" +
504 "</outer>\n";
505
506 String b = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
507 "<outer xmlns:NS2=\"http://namespace2\">\n" +
508 " <inner xmlns:NS2=\"http://namespace2/\">5</inner>\n" +
509 "</outer>\n";
510
511 assertXMLEqual(a, b);
512 } finally {
513 XMLUnit.setIgnoreWhitespace(startValueIgnoreWhitespace);
514 }
515 }
516
517 // Bug 585555
518 public void testNamespaceMatters() throws Exception
519 {
520 boolean startValueIgnoreWhitespace = XMLUnit.getIgnoreWhitespace();
521 try {
522 XMLUnit.setIgnoreWhitespace(true);
523 String a = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
524 "<outer xmlns=\"http://namespace2/\">\n" +
525 "</outer>";
526
527 String b = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
528 "<outer xmlns=\"http://namespace2\">\n" +
529 "</outer>\n";
530
531 assertXMLNotEqual(a, b);
532 } finally {
533 XMLUnit.setIgnoreWhitespace(startValueIgnoreWhitespace);
534 }
535 }
536
537 // Bug 741636
538 public void testXpathCount() throws Exception {
539 assertXpathEvaluatesTo("25", "count(//td)",
540 "<div><p>" +
541 "</p><table><tr><td><p>" +
542 "</p></td><td><p>" +
543 "</p></td><td><p>" +
544 "</p></td><td><p>" +
545 "</p></td><td><p>" +
546 "</p></td></tr><tr><td><p>" +
547 "</p></td><td><p>" +
548 "</p></td><td><p>" +
549 "</p></td><td><p>" +
550 "</p></td><td><p>" +
551 "</p></td></tr><tr><td><p>" +
552 "</p></td><td><p>" +
553 "</p></td><td><p>" +
554 "</p></td><td><p>" +
555 "</p></td><td><p>" +
556 "</p></td></tr><tr><td><p>" +
557 "</p></td><td><p>" +
558 "</p></td><td><p>" +
559 "</p></td><td><p>" +
560 "</p></td><td><p>" +
561 "</p></td></tr><tr><td><p>" +
562 "</p></td><td><p>" +
563 "</p></td><td><p>" +
564 "</p></td><td><p>" +
565 "</p></td><td><p>" +
566 "</p></td></tr></table></div>");
567 }
568
569 // bug 1418497
570 public void testAssertXpathExistsFails() throws Exception {
571 String xmlDocument = "<axrtable> <schema name=\"emptySchema\"><relation name=\"\"></relation></schema></axrtable>";
572 assertXpathExists("/axrtable/schema", xmlDocument);
573 }
574
575 // bug 3290264
576 public void testAssertXpathEqualsAndAttributes() throws Exception {
577 assertXpathsNotEqual("/foo/Bar/@a", "/foo/Bar",
578 "<foo><Bar a=\"1\" /></foo>");
579 assertXpathsNotEqual("/foo/Bar/@a", "/foo/Bar/@b",
580 "<foo><Bar a=\"1\" b=\"1\"/></foo>");
581 assertXpathsEqual("/foo/Bar/@a", "/foo/Bar/@a",
582 "<foo><Bar a=\"1\" b=\"2\"/></foo>");
583 }
584
585 // https://sourceforge.net/p/xmlunit/feature-requests/25/
586 public void testXpathEvaluatesToQualifiedName() throws Exception {
587 String faultDocument = "<env:Envelope "
588 + "xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>"
589 + "<env:Body><env:Fault><faultcode>env:Server</faultcode>"
590 + "<faultstring>marche pas</faultstring><detail/></env:Fault>"
591 + "</env:Body></env:Envelope>";
592 Map namespaces = new HashMap();
593 namespaces.put("env11", "http://schemas.xmlsoap.org/soap/envelope/");
594 XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
595 XMLAssert.assertXpathEvaluatesTo(QualifiedName.valueOf("env11:Server"),
596 "//env11:Envelope/env11:Body/"
597 + "env11:Fault/faultcode",
598 faultDocument);
599 }
600
601 public test_XMLTestCase(String name) {
602 super(name);
603 }
604
605 private static String addNamespaceToDocument(String original) {
606 int pos = original.indexOf(">");
607 return original.substring(0, pos) + " xmlns='" + TEST_NS + "'"
608 + original.substring(pos);
609 }
610
611 public void tearDown() {
612 XMLUnit.setXpathNamespaceContext(null);
613 }
614
615 /**
616 * returns the TestSuite containing this test
617 */
618 public static TestSuite suite(){
619 return new TestSuite(test_XMLTestCase.class);
620 }
621 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit;
37
38 import javax.xml.parsers.DocumentBuilderFactory;
39 import junit.framework.TestCase;
40 import junit.framework.TestSuite;
41
42 import org.custommonkey.xmlunit.exceptions.ConfigurationException;
43 import org.w3c.dom.Document;
44 import org.xml.sax.EntityResolver;
45 import org.xml.sax.helpers.DefaultHandler;
46
47 /**
48 * Test case for XMLUnit
49 */
50 public class test_XMLUnit extends TestCase{
51 /**
52 * Contructs a new test case.
53 */
54 public test_XMLUnit(String name){
55 super(name);
56 }
57
58 private String getDocumentBuilderFactoryImplClass() {
59 return DocumentBuilderFactory.newInstance().getClass().getName();
60 }
61
62 /**
63 * Test overiding the SAX parser used to parse control documents
64 */
65 public void testSetControlParser() throws Exception {
66 Object before = XMLUnit.newControlParser();
67 XMLUnit.setControlParser(getDocumentBuilderFactoryImplClass());
68 assertEquals("should be different", false,
69 before == XMLUnit.newControlParser());
70 }
71
72 public void testIgnoreWhitespace() throws Exception {
73 assertEquals("should not ignore whitespace by default",
74 false, XMLUnit.getIgnoreWhitespace());
75 XMLUnit.setIgnoreWhitespace(true);
76 String test="<test> monkey </test>";
77 String control="<test>monkey</test>";
78 assertEquals("Should be similar", true,
79 new Diff(control, test).similar());
80 try {
81 XMLUnit.setIgnoreWhitespace(false);
82 assertEquals("Should be different", false,
83 new Diff(control, test).similar());
84 } finally {
85 // restore default setting
86 XMLUnit.setIgnoreWhitespace(false);
87 }
88 }
89
90 /**
91 * Test overiding the SAX parser used to parse test documents
92 */
93 public void testSetTestParser() throws Exception {
94 Object before = XMLUnit.newTestParser();
95 XMLUnit.setTestParser(getDocumentBuilderFactoryImplClass());
96 assertEquals("should be different", false,
97 before==XMLUnit.newTestParser());
98 }
99
100 public void testSetTransformerFactory() throws Exception {
101 Object before = XMLUnit.getTransformerFactory();
102 XMLUnit.setTransformerFactory(before.getClass().getName());
103 assertEquals("should be different", false,
104 before==XMLUnit.getTransformerFactory());
105 }
106
107 public void testStripWhitespaceTransform() throws Exception {
108 Document doc = XMLUnit.buildTestDocument(
109 test_Constants.XML_WITH_WHITESPACE);
110 Transform transform = XMLUnit.getStripWhitespaceTransform(doc);
111 Diff diff = new Diff(test_Constants.XML_WITHOUT_WHITESPACE, transform);
112 assertTrue(diff.similar());
113 }
114
115 public void testXSLTVersion() {
116 try {
117 assertEquals("1.0", XMLUnit.getXSLTVersion());
118 assertEquals(XSLTConstants.XSLT_START, XMLUnit.getXSLTStart());
119 XMLUnit.setXSLTVersion("2.0");
120 assertTrue(XMLUnit.getXSLTStart()
121 .startsWith(XSLTConstants.XSLT_START_NO_VERSION));
122 assertTrue(XMLUnit.getXSLTStart().endsWith("\"2.0\">"));
123 try {
124 XMLUnit.setXSLTVersion("foo");
125 fail("foo is not a number");
126 } catch (ConfigurationException expected) {
127 }
128 try {
129 XMLUnit.setXSLTVersion("-1.0");
130 fail("-1.0 is negative");
131 } catch (ConfigurationException expected) {
132 }
133 } finally {
134 XMLUnit.setXSLTVersion("1.0");
135 }
136 }
137 }
0 /*
1 ******************************************************************
2 Copyright (c) 2001, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35 package org.custommonkey.xmlunit;
36
37 import junit.framework.TestCase;
38
39 import org.w3c.dom.Attr;
40 import org.w3c.dom.CDATASection;
41 import org.w3c.dom.Comment;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.Node;
45 import org.w3c.dom.NodeList;
46 import org.w3c.dom.ProcessingInstruction;
47 import org.w3c.dom.Text;
48
49 /**
50 * Testcase for XpathNodeTracker
51 */
52 public class test_XpathNodeTracker extends TestCase {
53 private XpathNodeTracker xpathNodeTracker;
54 private static final Node DUMMY_NODE = null;
55
56 public void testRootNode() {
57 xpathNodeTracker.visitedNode(DUMMY_NODE, "diary");
58 assertEquals("root node", "/diary[1]", xpathNodeTracker.toXpathString());
59 }
60
61 public void testOneLevelOfChildren() {
62 xpathNodeTracker.visitedNode(DUMMY_NODE, "diary");
63
64 xpathNodeTracker.indent();
65 assertEquals("before first child", "/diary[1]", xpathNodeTracker.toXpathString());
66
67 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
68 assertEquals("first child", "/diary[1]/event[1]", xpathNodeTracker.toXpathString());
69
70 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
71 assertEquals("2nd child", "/diary[1]/event[2]", xpathNodeTracker.toXpathString());
72
73 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
74 assertEquals("3rd child", "/diary[1]/event[3]", xpathNodeTracker.toXpathString());
75
76 xpathNodeTracker.visitedNode(DUMMY_NODE, "reminder");
77 assertEquals("4th child", "/diary[1]/reminder[1]", xpathNodeTracker.toXpathString());
78
79 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
80 assertEquals("5th child", "/diary[1]/event[4]", xpathNodeTracker.toXpathString());
81 }
82
83 public void testTwoLevelsOfChildren() {
84 xpathNodeTracker.visitedNode(DUMMY_NODE, "diary");
85
86 xpathNodeTracker.indent();
87 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
88
89 xpathNodeTracker.indent();
90 xpathNodeTracker.visitedNode(DUMMY_NODE, "details");
91 assertEquals("indented", "/diary[1]/event[1]/details[1]", xpathNodeTracker.toXpathString());
92
93 xpathNodeTracker.outdent();
94 xpathNodeTracker.visitedNode(DUMMY_NODE, "event");
95 assertEquals("outdented", "/diary[1]/event[2]", xpathNodeTracker.toXpathString());
96
97 xpathNodeTracker.indent();
98 xpathNodeTracker.visitedNode(DUMMY_NODE, "details");
99 assertEquals("re-indented", "/diary[1]/event[2]/details[1]", xpathNodeTracker.toXpathString());
100
101 xpathNodeTracker.outdent();
102 assertEquals("re-outdented", "/diary[1]/event[2]", xpathNodeTracker.toXpathString());
103
104 xpathNodeTracker.outdent();
105 assertEquals("outdented to root node", "/diary[1]", xpathNodeTracker.toXpathString());
106 }
107
108 public void testNodes() throws Exception {
109 Document doc = XMLUnit.newControlParser().newDocument();
110 Element element = doc.createElementNS("http://example.com/xmlunit", "eg:root");
111 xpathNodeTracker.visited(element);
112 assertEquals("root element", "/root[1]", xpathNodeTracker.toXpathString());
113
114 Attr attr = doc.createAttributeNS("http://example.com/xmlunit", "eg:type");
115 attr.setValue("qwerty");
116 element.setAttributeNodeNS(attr);
117 xpathNodeTracker.visited(attr);
118 assertEquals("root element attribute", "/root[1]/@type", xpathNodeTracker.toXpathString());
119
120 xpathNodeTracker.indent();
121
122 Comment comment = doc.createComment("testing a comment");
123 xpathNodeTracker.visited(comment);
124 assertEquals("comment", "/root[1]/comment()[1]", xpathNodeTracker.toXpathString());
125
126 ProcessingInstruction pi = doc.createProcessingInstruction("target","data");
127 xpathNodeTracker.visited(pi);
128 assertEquals("p-i", "/root[1]/processing-instruction()[1]", xpathNodeTracker.toXpathString());
129
130 Text text = doc.createTextNode("some text");
131 xpathNodeTracker.visited(text);
132 assertEquals("text", "/root[1]/text()[1]", xpathNodeTracker.toXpathString());
133
134 CDATASection cdata = doc.createCDATASection("some characters");
135 xpathNodeTracker.visited(cdata);
136 assertEquals("cdata", "/root[1]/text()[2]", xpathNodeTracker.toXpathString());
137 }
138
139 public void testRepeatNodesForTestTracker() throws Exception {
140 Document doc = XMLUnit.newControlParser().newDocument();
141 final Element element = doc.createElement("repeated");
142 final Element copy = doc.createElement("repeated");
143
144 NodeList nodeList = new NodeList() {
145 public Node item(int index) {
146 switch(index) {
147 case 0:
148 return element;
149 case 1:
150 return copy;
151 default:
152 return null;
153 }
154 }
155 public int getLength() {
156 return 2;
157 }
158 };
159 xpathNodeTracker.preloadNodeList(nodeList);
160
161
162 xpathNodeTracker.visited(element);
163 assertEquals("root element", "/repeated[1]", xpathNodeTracker.toXpathString());
164
165 xpathNodeTracker.visited(element);
166 assertEquals("visited root element again", "/repeated[1]", xpathNodeTracker.toXpathString());
167
168 xpathNodeTracker.visited(copy);
169 assertEquals("visited copy of root element", "/repeated[2]", xpathNodeTracker.toXpathString());
170 }
171
172 public void testRepeatNodesForControlTracker() throws Exception {
173 Document doc = XMLUnit.newControlParser().newDocument();
174 Element element = doc.createElement("repeated");
175
176 xpathNodeTracker.visited(element);
177 assertEquals("root element", "/repeated[1]", xpathNodeTracker.toXpathString());
178
179 xpathNodeTracker.visited(element);
180 assertEquals("visited root element again", "/repeated[2]", xpathNodeTracker.toXpathString());
181 }
182
183 // bug 1047364
184 public void testEmptyIndentOutdentRootNode() {
185 xpathNodeTracker.indent();
186 xpathNodeTracker.outdent();
187 xpathNodeTracker.visitedNode(DUMMY_NODE, "diary");
188 assertEquals("root node", "/diary[1]", xpathNodeTracker.toXpathString());
189 }
190
191 public void setUp() {
192 xpathNodeTracker = new XpathNodeTracker();
193 xpathNodeTracker.reset();
194 }
195
196 /**
197 * Constructor for test_XpathNodeTracker.
198 * @param name
199 */
200 public test_XpathNodeTracker(String name) {
201 super(name);
202 }
203
204 }
0 /*
1 ******************************************************************
2 Copyright (c) 200, Jeff Martin, Tim Bacon
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of the xmlunit.sourceforge.net nor the names
16 of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written
18 permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32
33 ******************************************************************
34 */
35
36 package org.custommonkey.xmlunit.util;
37
38 import junit.framework.TestCase;
39
40 /**
41 * Tests for IntegerBuffer
42 */
43 public class test_IntegerBuffer extends TestCase {
44
45 public void testToArrayEmpty() {
46 assertNotNull((new IntegerBuffer()).toIntArray());
47 assertEquals(0, (new IntegerBuffer()).toIntArray().length);
48 }
49
50 public void testSingleIntAppend() {
51 IntegerBuffer b = new IntegerBuffer();
52 b.append(1);
53 assertNotNull(b.toIntArray());
54 assertEquals(1, b.toIntArray().length);
55 assertEquals(1, b.toIntArray()[0]);
56 }
57
58 public void testArrayAppend() {
59 IntegerBuffer b = new IntegerBuffer();
60 b.append(new int[] {1, 2});
61 assertNotNull(b.toIntArray());
62 assertEquals(2, b.toIntArray().length);
63 for (int i = 0; i < 2; i++) {
64 assertEquals(i + 1, b.toIntArray()[i]);
65 }
66 }
67
68 public void testSingleIntAppendWithGrowth() {
69 IntegerBuffer b = new IntegerBuffer(1);
70 for (int i = 0; i < 2; i++) {
71 b.append(i);
72 }
73 assertNotNull(b.toIntArray());
74 assertEquals(2, b.toIntArray().length);
75 for (int i = 0; i < 2; i++) {
76 assertEquals(i, b.toIntArray()[i]);
77 }
78 }
79
80 public void testArrayAppendWithGrowth() {
81 IntegerBuffer b = new IntegerBuffer(1);
82 b.append(new int[] {1, 2});
83 assertNotNull(b.toIntArray());
84 assertEquals(2, b.toIntArray().length);
85 for (int i = 0; i < 2; i++) {
86 assertEquals(i + 1, b.toIntArray()[i]);
87 }
88 }
89
90 public void testSize() {
91 IntegerBuffer b = new IntegerBuffer();
92 assertEquals(0, b.size());
93 b.append(0);
94 assertEquals(1, b.size());
95 b.append(new int[] {1, 2});
96 assertEquals(3, b.size());
97 }
98
99 public void testCapacity() {
100 IntegerBuffer b = new IntegerBuffer(1);
101 assertEquals(1, b.capacity());
102 b.append(0);
103 assertEquals(1, b.capacity());
104 b.append(0);
105 assertTrue(b.capacity() > 1);
106 }
107
108 public void testIndexOfSimple() {
109 IntegerBuffer b = new IntegerBuffer();
110 int[] test = new int[] {1, 2, 3};
111 assertEquals(-1, b.indexOf(test));
112 b.append(test);
113 assertEquals(0, b.indexOf(test));
114 b.append(test);
115 assertEquals(0, b.indexOf(test));
116 }
117
118 public void testIndexOfWithOffset() {
119 IntegerBuffer b = new IntegerBuffer();
120 int[] test = new int[] {1, 2, 3};
121 b.append(0);
122 assertEquals(-1, b.indexOf(test));
123 b.append(test);
124 assertEquals(1, b.indexOf(test));
125 }
126
127 public void testIndexOfWithRepeatedInts() {
128 IntegerBuffer b = new IntegerBuffer();
129 int[] test = new int[] {1, 2, 3};
130 b.append(1);
131 assertEquals(-1, b.indexOf(test));
132 b.append(test);
133 assertEquals(1, b.indexOf(test));
134 }
135
136 public void testIndexOfSupSequenceIsThere() {
137 IntegerBuffer b = new IntegerBuffer();
138 int[] test = new int[] {1, 2, 3};
139 b.append(new int[] {1, 2});
140 b.append(4);
141 assertEquals(-1, b.indexOf(test));
142 }
143
144 public void testAllBytes() {
145 IntegerBuffer buf = new IntegerBuffer();
146 for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
147 buf.append(b);
148 }
149 buf.append(Byte.MAX_VALUE);
150 int[] is = buf.toIntArray();
151 for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
152 assertEquals((byte) i, is[i + Math.abs(Byte.MIN_VALUE)]);
153 }
154 }
155
156 public void testAllChars() {
157 IntegerBuffer buf = new IntegerBuffer();
158 for (char c = Character.MIN_VALUE; c < Character.MAX_VALUE; c++) {
159 buf.append(c);
160 }
161 buf.append(Character.MAX_VALUE);
162 int[] is = buf.toIntArray();
163 for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; i++) {
164 assertEquals((char) i, is[i + Math.abs(Character.MIN_VALUE)]);
165 }
166 }
167 }
Binary diff not shown
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A. Changes</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s06.html" title="6. DOM Tree Walking"><link rel="next" href="apas02.html" title="A.2. Changes from XMLUnit 1.1 to 1.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A. Changes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="apas02.html">Next</a></td></tr></table><hr></div><div class="appendix"><div class="titlepage"><div><div><h2 class="title"><a name="changes"></a>A. Changes</h2></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.1"></a>A.1. Changes from XMLUnit 1.0 to 1.1</h3></div></div></div>
4
5
6 <p>XMLUnit 1.1's main focus was to add two features that have
7 been asked for repeatedly:</p>
8
9 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Support for XML Namespaces in XPath
10 processing</li><li class="listitem">Support for XML Schema validation.</li></ul></div>
11
12 <p>In addition some JAXP features that have been added after
13 the release of XMLUnit 1.0 are now supported - most notably
14 XPath support - and all reported bugs and feature requests have
15 been addressed.</p>
16
17 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.1"></a>A.1.1. Breaking Changes</h4></div></div></div>
18
19
20 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
21 <code class="literal">XMLTestCase</code> is now abstract. You
22 probably have never created instances of this class
23 without subclassing it, but if you did, your code will now
24 break. You will most likely want to look at the
25 <code class="literal">XMLAssert</code> class.
26 </li><li class="listitem">
27 <p>All methods that have been deprecated in XMLUnit 1.0
28 have been removed.</p>
29 </li><li class="listitem">
30 <p>All methods that had been declared to throw
31 <code class="literal">TransformerConfigurationException</code> or
32 <code class="literal">ParserConfigurationException</code> now no
33 longer declare it. Exceptions of these types cannot be
34 recovered from anyway, so XMLUnit will now wrap them in a
35 <code class="literal">org.custommonkey.xmlunit.exceptions.ConfigurationException</code>
36 which is an unchecked exception.</p>
37
38 <p>This change doesn't have a big impact on your tests,
39 but if you tried to catch these exceptions they will now
40 bypass your catch blocks.</p>
41 </li><li class="listitem">
42 <p>A new type of <code class="literal">Difference</code>
43 (<code class="literal">CHILD_NODE_NOT_FOUND_ID</code>) has been
44 added. It will be raised for the excess children if the
45 control element has more child nodes than the test element
46 - or vice versa.</p>
47
48 <p>Prior to XMLUnit 1.1 a <code class="literal">Difference</code>
49 of either <code class="literal">ELEMENT_TAG_NAME_ID</code> or
50 <code class="literal">NODE_TYPE_ID</code> would have been raised if
51 the control element had more children. The excess
52 children were compared to the very first child node of the
53 test element. Excess children of the test element were
54 not reported at all.</p>
55 </li><li class="listitem">
56 <p>The <code class="literal">schemaLocation</code> and
57 <code class="literal">noNamespaceSchemaLocation</code> attributes of
58 the XMLSchema-Instance Namespace are now treated in a
59 different way from "normal" attributes. They will be
60 flagged as new kinds of <code class="literal">Difference</code> that
61 is recoverable.</p>
62
63 <p>This means that two pieces of XML that were
64 different in XMLUnit 1.0 because they differed in one of
65 the two attributes will be similar in XMLUnit 1.1.</p>
66 </li><li class="listitem">
67 <p>When comparing two elements that differ on
68 attributes the comparison is now symmetric.</p>
69
70 <p>In XMLUnit 1.0 if an attribute was present on the
71 test but not the control element this wasn't flagged as a
72 <code class="literal">Difference</code>; in XMLUnit 1.1 it
73 is.</p>
74
75 <p>In most practical cases this doesn't cause any
76 problems since the two elements either have a different
77 number of attributes or there are attributes in the
78 control element that are missing in the test element - so
79 the pieces of XML have been flagged as different before as
80 well. If you are using <code class="literal">DetailedDiff</code>
81 this change may lead to more detected
82 <code class="literal">Difference</code>s, though.</p>
83 </li></ul></div>
84 </div>
85
86 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.1"></a>A.1.2. New Features</h4></div></div></div>
87
88
89 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">XMLUnit 1.0 shipped with rudimentary support for
90 XML Schema validation (it worked with Apache Xerces-J but no
91 other parsers). XMLUnit 1.1 supports Schema validation for
92 any JAXP compliant XML parser (that supports Schema itself).
93 You can also tell XMLUnit where to look for the XML Schema
94 definitions. See <a class="xref" href="ar01s04.html#XML%20Schema%20Validation" title="4.1.2. XML Schema Validation">Section 4.1.2, &#8220;XML Schema Validation&#8221;</a> for
95 details.</li><li class="listitem">XPath support has undergone significant changes,
96 see <a class="xref" href="ar01s05.html" title="5. XPath Tests">Section 5, &#8220;XPath Tests&#8221;</a> for more details. In particular
97 XMLUnit will now use <code class="literal">javax.xml.xpath</code> if
98 it is available (which also helps to avoid the buggy XSLTC
99 version that is the default transformer engine in Java 5)
100 and supports XML namespaces.</li><li class="listitem">Several new configuration options have been added,
101 see <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8. Configuration Options">Section 3.8, &#8220;Configuration Options&#8221;</a>.
102 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">Treat CDATA sections and Texts alike. <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1262148&amp;group_id=23187&amp;atid=377768" target="_top">Issue
103 1262148</a>.</li><li class="listitem">Ignore differences in Text whitespace. <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=754812&amp;group_id=23187&amp;atid=377771" target="_top">Issue
104 754812</a>.</li><li class="listitem">Ignore comments completely. <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=707255&amp;group_id=23187&amp;atid=377770" target="_top">Issue
105 707255</a>.</li><li class="listitem">Ignore the order of attributes.</li></ul></div>
106 </li><li class="listitem">It is now possible to provide a custom
107 <code class="literal">org.xml.sax.EntityResolver</code> for control
108 and test parsers.</li><li class="listitem">It is now possible to provide a custom
109 <code class="literal">javax.xml.transform.URIResolver</code> for
110 transformations.</li><li class="listitem">New overloads have been added that allow
111 <code class="literal">org.xml.sax.InputSource</code> to be used as a
112 "piece of XML" in many classes.</li><li class="listitem"><code class="literal">Validator</code> will now use the
113 custom <code class="literal">EntityResolver</code> <a class="link" href="ar01s02.html#EntityResolver" title="2.4.2. EntityResolver">configured</a> for the "control"
114 parser as a fallback.</li><li class="listitem">
115 <p>A new package
116 <code class="literal">org.custommonkey.xmlunit.examples</code> has
117 been added that showcases some of XMLUnit's abilities.
118 It currently contains two classes:</p>
119
120 <div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
121 <code class="literal">MultiLevelElementNameAndTextQualifier</code>
122 see <a class="xref" href="ar01s03.html#MultiLevelElementNameAndTextQualifier" title="3.4.5. org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier">Section 3.4.5, &#8220;<code class="literal">org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier</code>&#8221;</a> for
123 a description.</li><li class="listitem"><code class="literal">XPathRegexAssert</code> that
124 provides a JUnit 3.x like
125 <code class="literal">assertXPathMatches</code> method to verify
126 that the string-ified value of an XPath match matches a
127 given regular expression (requires JDK 1.4 or
128 above).</li></ol></div>
129 </li></ul></div>
130 </div>
131
132 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.1"></a>A.1.3. Important Bug Fixes</h4></div></div></div>
133
134
135 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ElementNameAndAttributeQualifier</code>
136 would throw an <code class="literal">NullPointerException</code> if
137 the control piece of XML contained attributes that were
138 missing in the test piece of XML. <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=952920&amp;group_id=23187&amp;atid=377768" target="_top">Issue
139 952920</a>.</li><li class="listitem">
140 <code class="literal">XMLTestCase.assertXMLNotEqual(String, Reader,
141 Reader)</code> delegated to
142 <code class="literal">assertXMLEqual</code> instead of
143 <code class="literal">assertXMLNotEqual</code> internally, negating
144 the assertion's logic. <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=956372&amp;group_id=23187&amp;atid=377768" target="_top">Issue
145 956372</a>.</li><li class="listitem"><code class="literal">XMLTestCase.assertXMLIdentical(Diff,
146 boolean)</code> delegated to
147 <code class="literal">assertXMLEqual</code>, weakening the
148 assertion.</li><li class="listitem">Under certain circumstances the reported XPath
149 expressions for nodes that showed differences were wrong.
150 XMLUnit could lose the root element or erroneously append an
151 extra attribute name. Issues <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1047364&amp;group_id=23187&amp;atid=377768" target="_top">1047364</a>
152 and <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1027863&amp;group_id=23187&amp;atid=377770" target="_top">1027863</a>.</li><li class="listitem">
153 <code class="literal">TolerantSaxParser</code>'s logic in
154 <code class="literal">characters</code> was broken and could cause
155 <code class="literal">StringIndexOutOfBoundsException</code>s.
156 <a class="ulink" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1150234&amp;group_id=23187&amp;atid=377768" target="_top">Issue 1150234</a>.</li></ul></div>
157 </div>
158 </div>
159
160
161
162
163
164
165
166
167
168
169
170 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="apas02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6. DOM Tree Walking </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.2. Changes from XMLUnit 1.1 to 1.2</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A.2. Changes from XMLUnit 1.1 to 1.2</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="apa.html" title="A. Changes"><link rel="prev" href="apa.html" title="A. Changes"><link rel="next" href="apas03.html" title="A.3. Changes from XMLUnit 1.2 to 1.3"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.2. Changes from XMLUnit 1.1 to 1.2</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apa.html">Prev</a> </td><th width="60%" align="center">A. Changes</th><td width="20%" align="right"> <a accesskey="n" href="apas03.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.2"></a>A.2. Changes from XMLUnit 1.1 to 1.2</h3></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.2"></a>A.2.1. Breaking Changes</h4></div></div></div>
4
5
6 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
7 If XMLUnit detects that it cannot match a certain node
8 (i.e. it encounters
9 a <code class="literal">CHILD_NODE_NOT_FOUND</code>
10 kind of difference) the XPath for the "missing" node will
11 be null. It used to be some random XPath of a different node.
12 </li><li class="listitem">
13 <code class="literal">XMLUnit.setIgnoreDiffBetweenTextAndCDATA</code>
14 now also
15 sets <code class="literal">DocumentBuilderFactory.setCoalescing</code>.
16 This has been done so that whitespace differences can be
17 resolved according to the corresponding flags even in the
18 presence of CDATA
19 sections. <a class="ulink" href="" target="_top">Issue
20 1903923</a>.</li><li class="listitem">
21 Two protected methods
22 in <code class="literal">SimpleXPathEngine</code> (which you
23 shouldn't extend anyway) have added XpathException to
24 their throws list.
25 </li></ul></div>
26 </div>
27
28 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.2"></a>A.2.2. New Features</h4></div></div></div>
29
30
31 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The <code class="literal">SAXParserFactory</code> used
32 by <code class="literal">Validator</code> can now be configured
33 completely. <a class="ulink" href="" target="_top">Issue
34 1903928</a>.</li><li class="listitem">A new
35 class <code class="literal">org.custommonkey.xmlunit.jaxp13.Validator</code>
36 can be used to validate schema definitions and schema
37 instances using the <code class="literal">javax.xml.validation</code>
38 package of JAXP 1.3. Depending on your JAXP implementation
39 this may allow you to validate documents against schema
40 definitions written in RELAX NG or other schema languages in
41 addition to W3C XML Schema. See
42 <a class="xref" href="ar01s04.html#JAXP%201.3%20Validation" title="4.4. JAXP 1.3 Validation">Section 4.4, &#8220;JAXP 1.3 Validation&#8221;</a> for details.</li><li class="listitem"><code class="literal">DifferenceListener</code> can now
43 "upgrade" recoverable differences to non-recoverable by
44 returning <code class="literal">RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT</code>
45 in the <code class="literal">differenceFound</code>
46 method. <a class="ulink" href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1854284&amp;group_id=23187&amp;atid=377771" target="_top">Issue
47 1854284</a>.</li><li class="listitem">A new callback
48 interface <code class="literal">MatchTracker</code> is now notified on
49 successful matches of Nodes. For more details see
50 <a class="xref" href="ar01s03.html#MatchTracker" title="3.6. MatchTracker">Section 3.6, &#8220;<code class="literal">MatchTracker</code>&#8221;</a>. <a class="ulink" href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1860491&amp;group_id=23187&amp;atid=377771" target="_top">Issue
51 1860491</a>.</li><li class="listitem">It is now possible to have more control over
52 whether the parser expand entity references or not by
53 using <code class="literal">XMLUnit.setExpandEntityReferences</code>,
54 see <a class="xref" href="ar01s03.html#Entity%20Reference%20Expansion" title="3.8.5. Entity Reference Expansion">Section 3.8.5, &#8220;Entity Reference Expansion&#8221;</a>. <a class="ulink" href="" target="_top">Issue
55 1877458</a>.</li><li class="listitem">New examples have been added:
56 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><code class="literal">RecursiveElementNameAndTextQualifier</code>
57 - a more flexible <code class="literal">ElementQualifier</code>
58 that fills the same need as
59 <code class="literal">MultiLevelElementNameAndTextQualifier</code>
60 See
61 <a class="xref" href="ar01s03.html#RecursiveElementNameAndTextQualifier" title="3.4.4. org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier">Section 3.4.4, &#8220;<code class="literal">org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</code>&#8221;</a>
62 for more details.</li><li class="listitem"><code class="literal">CaseInsensitiveDifferenceListener</code>
63 a - <code class="literal">DifferenceListener</code> that ignores
64 case when comparing texts.</li><li class="listitem"><code class="literal">FloatingPointTolerantDifferenceListener</code>
65 a - <code class="literal">DifferenceListener</code> that tries
66 to parse texts as floating point numbers and compares
67 them using a configurable tolerance.</li></ul></div>
68 </li></ul></div>
69 </div>
70
71 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.2"></a>A.2.3. Important Bug Fixes</h4></div></div></div>
72
73
74 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
75 If XMLUnit couldn't match nodes (i.e. it encountered
76 a <code class="literal">CHILD_NODE_NOT_FOUND</code> kind of
77 difference), the XPath expressions of the node details
78 have been random. <a class="ulink" href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=1860681&amp;group_id=23187&amp;atid=377768" target="_top">Issue 1860681</a>.
79 </li></ul></div>
80 </div>
81 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apa.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="apas03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A. Changes </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.3. Changes from XMLUnit 1.2 to 1.3</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A.3. Changes from XMLUnit 1.2 to 1.3</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="apa.html" title="A. Changes"><link rel="prev" href="apas02.html" title="A.2. Changes from XMLUnit 1.1 to 1.2"><link rel="next" href="apas04.html" title="A.4. Changes from XMLUnit 1.3 to 1.4"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.3. Changes from XMLUnit 1.2 to 1.3</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apas02.html">Prev</a> </td><th width="60%" align="center">A. Changes</th><td width="20%" align="right"> <a accesskey="n" href="apas04.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.3"></a>A.3. Changes from XMLUnit 1.2 to 1.3</h3></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.3"></a>A.3.1. Breaking Changes</h4></div></div></div>
4
5
6
7 </div>
8
9 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.3"></a>A.3.2. New Features</h4></div></div></div>
10
11
12 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
13 If XMLUnit doesn't find a matching Element for a control
14 Element, it will match it against the first unmatched test
15 Element (if there is one) instead of creating
16 a <code class="literal">CHILD_NODE_NOT_FOUND</code> Difference.
17 There now is a new configuration
18 option <code class="literal">compareUnmatched</code> in
19 the <code class="literal">XMLUnit</code> class that can be used to
20 turn off this behavior - as a result
21 two <code class="literal">CHILD_NODE_NOT_FOUND</code> Differences
22 (one for the unmatched control Element and one for an
23 unmatched test Element) will be created instead of a
24 single Difference comparing the two likely unrelated
25 nodes. See <a class="xref" href="ar01s03.html#Comparison%20of%20Unmatched%20Elements" title="3.8.6. Comparison of Unmatched Elements">Section 3.8.6, &#8220;Comparison of Unmatched Elements&#8221;</a>.
26 <a class="ulink" href="https://sourceforge.net/tracker/?func=detail&amp;aid=2758280&amp;group_id=23187&amp;atid=377768" target="_top">Issue 2758280</a>.
27 </li></ul></div>
28 </div>
29
30 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.3"></a>A.3.3. Important Bug Fixes</h4></div></div></div>
31
32
33 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
34 If XMLUnit couldn't match attributes (i.e. it encountered
35 a <code class="literal">ATTR_NAME_NOT_FOUND_ID</code> kind of
36 difference), the XPath expressions of the node details
37 have been random. <a class="ulink" href="https://sourceforge.net/tracker/index.php?func=detail&amp;aid=2386807&amp;group_id=23187&amp;atid=377768" target="_top">Issue 2386807</a>.
38 </li><li class="listitem">
39 In some cases XMLUnit matched test nodes to multiple
40 control nodes and then created a "missing child"
41 difference for remaining test nodes even though they would
42 have been valid targets for control node matches as well.
43 <a class="ulink" href="https://sourceforge.net/tracker/?func=detail&amp;aid=2807167&amp;group_id=23187&amp;atid=377768" target="_top">Issue 2807167</a>.
44 </li></ul></div>
45 </div>
46 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apas02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="apas04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.2. Changes from XMLUnit 1.1 to 1.2 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.4. Changes from XMLUnit 1.3 to 1.4</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A.4. Changes from XMLUnit 1.3 to 1.4</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="apa.html" title="A. Changes"><link rel="prev" href="apas03.html" title="A.3. Changes from XMLUnit 1.2 to 1.3"><link rel="next" href="apas05.html" title="A.5. Changes from XMLUnit 1.4 to 1.5"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.4. Changes from XMLUnit 1.3 to 1.4</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apas03.html">Prev</a> </td><th width="60%" align="center">A. Changes</th><td width="20%" align="right"> <a accesskey="n" href="apas05.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.4"></a>A.4. Changes from XMLUnit 1.3 to 1.4</h3></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.4"></a>A.4.1. Breaking Changes</h4></div></div></div>
4
5
6
7 </div>
8
9 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.4"></a>A.4.2. New Features</h4></div></div></div>
10
11
12 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
13 xsi:type attributes now have their value interpreted as a
14 QName and will compare as identical if their namespace URI
15 and local names match even if they use different
16 prefixes. <a class="ulink" href="https://sourceforge.net/tracker/?func=detail&amp;aid=3602981&amp;group_id=23187&amp;atid=377771" target="_top">Issue 3602981</a>
17 </li></ul></div>
18 </div>
19
20 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.4"></a>A.4.3. Important Bug Fixes</h4></div></div></div>
21
22
23 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
24 <code class="literal">XMLTestCase</code>'s and <code class="literal">XMLAssert</code>'s
25 <code class="literal">assertXpathsEqual</code> methods threw an
26 exception when at least one XPath matched an attribute. <a class="ulink" href="https://sourceforge.net/tracker/?func=detail&amp;aid=3290264&amp;group_id=23187&amp;atid=377768" target="_top">Issue 377768</a>.
27 </li><li class="listitem">
28 <code class="literal">FloatingPointTolerantDifferenceListener</code>
29 expected numbers to differ by less than the given
30 tolerance rather than "less or equal" than as the docs said.
31 <a class="ulink" href="" target="_top">Issue
32 3593368</a>
33 </li></ul></div>
34 </div>
35 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apas03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="apas05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.3. Changes from XMLUnit 1.2 to 1.3 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.5. Changes from XMLUnit 1.4 to 1.5</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A.5. Changes from XMLUnit 1.4 to 1.5</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="apa.html" title="A. Changes"><link rel="prev" href="apas04.html" title="A.4. Changes from XMLUnit 1.3 to 1.4"><link rel="next" href="apas06.html" title="A.6. Changes from XMLUnit 1.5 to 1.6"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.5. Changes from XMLUnit 1.4 to 1.5</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apas04.html">Prev</a> </td><th width="60%" align="center">A. Changes</th><td width="20%" align="right"> <a accesskey="n" href="apas06.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.5"></a>A.5. Changes from XMLUnit 1.4 to 1.5</h3></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.5"></a>A.5.1. Breaking Changes</h4></div></div></div>
4
5
6 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
7 If one node in the comparison has children while the other
8 one has not, XMLUnit 1.5 will signal a
9 <code class="literal">CHILD_NODELIST_LENGTH</code> difference and
10 <code class="literal">CHILD_NODE_NOT_FOUND</code>
11 differences for each child node of the node that has
12 children in addition to a <code class="literal">HAS_CHILD_NODES</code> difference.
13 <a class="ulink" href="" target="_top">Issue
14 60</a>
15 </li></ul></div>
16 </div>
17
18 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.5"></a>A.5.2. New Features</h4></div></div></div>
19
20
21 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
22 </li></ul></div>
23 </div>
24
25 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.5"></a>A.5.3. Important Bug Fixes</h4></div></div></div>
26
27
28 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
29 <code class="literal">RecursiveElementNameAndTextQualifier</code> had some indices
30 reversed leading to wrong results in some cases.
31 <a class="ulink" href="" target="_top">Issue
32 62</a>
33 </li></ul></div>
34 </div>
35 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apas04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="apas06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.4. Changes from XMLUnit 1.3 to 1.4 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.6. Changes from XMLUnit 1.5 to 1.6</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>A.6. Changes from XMLUnit 1.5 to 1.6</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="apa.html" title="A. Changes"><link rel="prev" href="apas05.html" title="A.5. Changes from XMLUnit 1.4 to 1.5"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.6. Changes from XMLUnit 1.5 to 1.6</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apas05.html">Prev</a> </td><th width="60%" align="center">A. Changes</th><td width="20%" align="right"> </td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Changes%201.6"></a>A.6. Changes from XMLUnit 1.5 to 1.6</h3></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Breaking%20Changes%201.6"></a>A.6.1. Breaking Changes</h4></div></div></div>
4
5
6 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
7 In cases of <code class="literal">ATTR_NAME_NOT_FOUND</code> and
8 <code class="literal">CHILD_NODE_NOT_FOUND</code> differences the
9 value used to be the local name of the missing attribute
10 or node. It will now be a Java5-QName-like
11 <code class="literal">{NS-URI}LOCAL-NAME</code> string if the
12 attribute or node belonged to an XML namespace.
13 <a class="ulink" href="" target="_top">Issue
14 65</a>
15 </li></ul></div>
16 </div>
17
18 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="New%20Features%201.6"></a>A.6.2. New Features</h4></div></div></div>
19
20
21 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
22 New <code class="literal">assertXpathEvaluatesTo</code>
23 overloads in <code class="literal">XMLAssert</code> and a new
24 <code class="literal">QualifiedName</code> class
25 can be used to assert the stringified result of an XPath
26 expression is actually a qualified name.
27 <a class="ulink" href="" target="_top">Feature
28 Request 25</a>
29 </li></ul></div>
30 </div>
31
32 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Bugfixes%201.6"></a>A.6.3. Important Bug Fixes</h4></div></div></div>
33
34
35 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
36 The JAXP 1.3 based validator ignored
37 <code class="literal">xsi:namespaceLocation</code> and
38 <code class="literal">xsi:noNamespaceLocation</code> attributes.
39 They will now be used if you don't specify any sources at
40 all, but are still ignored if you
41 specify any schema sources - since this is the way
42 <code class="literal">javax.xml.validation</code> works.
43 <a class="ulink" href="" target="_top">Issue
44 64</a>
45 </li><li class="listitem">
46 When an attribute cannot be found (a
47 <code class="literal">ATTR_NAME_NOT_FOUND</code> difference) the
48 XPath on the side where the attribute exists will now
49 point to the attribute itself rather than its owning element.
50 <a class="ulink" href="" target="_top">Feature
51 Request 33</a>
52 </li></ul></div>
53 </div>
54 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apas05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="apa.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">A.5. Changes from XMLUnit 1.4 to 1.5 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>2. Using XMLUnit</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="index.html" title="XMLUnit Java User's Guide"><link rel="next" href="ar01s03.html" title="3. Comparing Pieces of XML"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2. Using XMLUnit</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Using%20XMLUnit"></a>2. Using XMLUnit</h2></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Requirements"></a>2.1. Requirements</h3></div></div></div>
4
5
6 <p>XMLUnit requires a JAXP compliant XML parser virtually
7 everywhere. Several features of XMLUnit also require a JAXP
8 compliant XSLT transformer. If it is available, a JAXP
9 compliant XPath engine will be used for XPath tests.</p>
10
11 <p>To build XMLUnit at least JAXP 1.2 is required, this is
12 the version provided by the Java class library in JDK 1.4. The
13 JAXP 1.3 (i.e. Java5 and above) XPath engine can only be built
14 when JAXP 1.3 is available.</p>
15
16 <p>As long as you don't require support for XML Namespaces or
17 XML Schema, any JAXP 1.1 compliant implementations should work
18 at runtime. For namespace and schema support you will need a
19 parser that complies to JAXP 1.2 and supports the required
20 feature. The XML parser shipping with JDK 1.4 (a version of
21 Apache Crimson) for example is compliant to JAXP 1.2 but doesn't
22 support Schema validation.</p>
23
24 <p>XMLUnit is supposed to build and run on any Java version
25 after 1.3 (at least no new hard JDK 1.4 dependencies have been
26 added in XMLUnit 1.1), but it has only been tested on JDK 1.4.2
27 and above.</p>
28
29 <p>To build XMLUnit JUnit 3.x (only tested with JUnit 3.8.x)
30 is required. It is not required at runtime unless you intend to
31 use the <code class="literal">XMLTestCase</code> or
32 <code class="literal">XMLAssert</code> classes.</p>
33 </div>
34
35 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Basic%20Usage"></a>2.2. Basic Usage</h3></div></div></div>
36
37
38 <p>XMLUnit consists of a few classes all living in the
39 <code class="literal">org.custommonkey.xmlunit</code> package. You can
40 use these classes directly from your code, no matter whether you
41 are writing a unit test or want to use XMLUnit's features for
42 any other purpose.</p>
43
44 <p>This section provides a few hints of where to start if you
45 want to use a certain feature of XMLUnit, more details can be
46 found in the more specific sections later in this
47 document.</p>
48
49 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Basic:%20Comparing%20Pieces%20of%20XML"></a>2.2.1. Comparing Pieces of XML</h4></div></div></div>
50
51
52 <p>Heart and soul of XMLUnit's comparison engine is
53 <code class="literal">DifferenceEngine</code> but most of the time you
54 will use it indirectly via the <code class="literal">Diff</code>
55 class.</p>
56
57 <p>You can influence the engine by providing (custom)
58 implementations for various interfaces and by setting a couple
59 of options on the <code class="literal">XMLUnit</code> class.</p>
60
61 <p>More information is available in <a class="xref" href="ar01s03.html" title="3. Comparing Pieces of XML">Section 3, &#8220;Comparing Pieces of XML&#8221;</a>.</p>
62
63 </div>
64
65 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Basic:%20Validating"></a>2.2.2. Validating</h4></div></div></div>
66
67 <p>All validation happens in the
68 <code class="literal">Validator</code> class. The default is to
69 validate against a DTD, but XML Schema validation can be
70 enabled by an option (see
71 <code class="literal">Validator.useXMLSchema</code>).</p>
72
73 <p>Several options of the <code class="literal">XMLUnit</code> class
74 affect validation.</p>
75
76 <p>More information is available in <a class="xref" href="ar01s04.html" title="4. Validating XML Documents">Section 4, &#8220;Validating XML Documents&#8221;</a>.</p>
77
78 </div>
79
80 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="XSLT%20Transformations"></a>2.2.3. XSLT Transformations</h4></div></div></div>
81
82 <p>The <code class="literal">Transform</code> class provides an easy
83 to use layer on top of JAXP's transformations. An instance of
84 this class is initialized with the source document and a
85 stylesheet and the result of the transformation can be
86 retrieved as a <code class="literal">String</code> or DOM
87 <code class="literal">Document</code>.</p>
88
89 <p>The output of <code class="literal">Transform</code> can be used
90 as input to comparisons, validations, XPath tests and so on.
91 There is no detailed sections on transformations since they
92 are really only a different way to create input for the rest
93 of XMLUnit's machinery. Examples can be found in <a class="xref" href="index.html#Comparing%20XML%20Transformations" title="1.6. Comparing XML Transformations">Section 1.6, &#8220;Comparing XML Transformations&#8221;</a>.</p>
94
95 <p>It is possible to provide a custom
96 <code class="literal">javax.xml.transform.URIResolver</code> via the
97 <code class="literal">XMLUnit.setURIResolver</code> method.</p>
98
99 <p>You can access the underlying XSLT transformer via
100 <code class="literal">XMLUnit.getTransformerFactory</code>.</p>
101 </div>
102
103 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="XPath%20Engine"></a>2.2.4. XPath Engine</h4></div></div></div>
104
105
106 <p>The central piece of XMLUnit's XPath support is the
107 <code class="literal">XpathEngine</code> interface. Currently two
108 implementations of the interface exist,
109 <code class="literal">SimpleXpathEngine</code> and
110 <code class="literal">org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</code>.</p>
111
112 <p><code class="literal">SimpleXpathEngine</code> is a very basic
113 implementation that uses your XSLT transformer under the
114 covers. This also means it will expose you to the bugs found
115 in your transformer like the transformer claiming a stylesheet
116 couldn't be compiled for very basic XPath expressions. This
117 has been reported to be the case for JDK 1.5.</p>
118
119 <p><code class="literal">org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</code>
120 uses JAXP 1.3's <code class="literal">javax.xml.xpath</code> package and
121 seems to work more reliable, stable and performant than
122 <code class="literal">SimpleXpathEngine</code>.</p>
123
124 <p>You use the <code class="literal">XMLUnit.newXpathEngine</code>
125 method to obtain an instance of the
126 <code class="literal">XpathEngine</code>. As of XMLUnit 1.1 this will
127 try to use JAXP 1.3 if it is available and fall back to
128 <code class="literal">SimpleXpathEngine</code>.</p>
129
130 <p>Instances of <code class="literal">XpathEngine</code> can return
131 the results of XPath queries either as DOM
132 <code class="literal">NodeList</code> or plain
133 <code class="literal">String</code>s.</p>
134
135 <p>More information is available in <a class="xref" href="ar01s05.html" title="5. XPath Tests">Section 5, &#8220;XPath Tests&#8221;</a>.</p>
136 </div>
137
138 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Basic:%20DOM%20Tree%20Walking"></a>2.2.5. DOM Tree Walking</h4></div></div></div>
139
140
141 <p>To test pieces of XML by traversing the DOM tree you use
142 the <code class="literal">NodeTester</code> class. Each DOM
143 <code class="literal">Node</code> will be passed to a
144 <code class="literal">NodeTester</code> implementation you provide. The
145 <code class="literal">AbstractNodeTester</code> class is provided as a
146 NullObject Pattern base class for implementations of your
147 own.</p>
148
149 <p>More information is available in <a class="xref" href="ar01s06.html" title="6. DOM Tree Walking">Section 6, &#8220;DOM Tree Walking&#8221;</a>.</p>
150 </div>
151 </div>
152
153 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Using%20XMLUnit%20With%20JUnit%203.x"></a>2.3. Using XMLUnit With JUnit 3.x</h3></div></div></div>
154
155
156 <p>Initially XMLUnit was tightly coupled to JUnit and the
157 recommended approach was to write unit tests by inheriting from
158 the <code class="literal">XMLTestCase</code> class.
159 <code class="literal">XMLTestCase</code> provides a pretty long list of
160 <code class="literal">assert...</code> methods that may simplify your
161 interaction with XMLUnit's internals in many common
162 cases.</p>
163
164 <p>The <code class="literal">XMLAssert</code> class provides the same
165 set of <code class="literal">assert...</code>s as static methods. Use
166 <code class="literal">XMLAssert</code> instead of
167 <code class="literal">XMLTestCase</code> for your unit tests if you can't
168 or don't want to inherit from
169 <code class="literal">XMLTestCase</code>.</p>
170
171 <p>All power of XMLUnit is available whether you use
172 <code class="literal">XMLTestCase</code> and/or
173 <code class="literal">XMLAssert</code> or the underlying API directly. If
174 you are using JUnit 3.x then using the specific classes may prove
175 to be more convenient.</p>
176
177 </div>
178
179 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Common%20Configuration%20Options"></a>2.4. Common Configuration Options</h3></div></div></div>
180
181
182 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="JAXP"></a>2.4.1. JAXP</h4></div></div></div>
183
184
185 <p>If you are using a JDK 1.4 or later, your Java class
186 library already contains the required XML parsers and XSLT
187 transformers. Still you may want to use a different
188 parser/transformer than the one of your JDK - in particular
189 since the versions shipping with some JDKs are known to
190 contain serious bugs.</p>
191
192 <p>As described in <a class="xref" href="index.html#Configuring%20XMLUnit" title="1.4. Configuring XMLUnit">Section 1.4, &#8220;Configuring XMLUnit&#8221;</a>
193 there are two main approaches to choose the XML parser of XSLT
194 transformer: System properties and setters in the
195 <code class="literal">XMLUnit</code> class.</p>
196
197 <p>If you use system properties you have the advantage that
198 your choice affects the whole JAXP system, whether it is used
199 inside of XMLUnit or not. If you are using JDK 1.4 or later
200 you may also want to review the <a class="ulink" href="http://java.sun.com/j2se/1.4.2/docs/guide/standards/" target="_top">Endorsed
201 Standards Override Mechanism</a> to use a different
202 parser/transformer than the one shipping with your JDK.</p>
203
204 <p>The second option - using the <code class="literal">XMLUnit</code>
205 class - allows you to use different parsers for control and
206 test documents, it even allows you to use different parsers
207 for different test cases, if you really want to stretch it
208 that far. It may also work for JDK 1.4 and above, even if you
209 don't override the endorsed standards libraries.</p>
210
211 <p>You can access the underlying JAXP parser by
212 <code class="literal">XMLUnit.newControlParser</code>,
213 <code class="literal">XMLUnit.newTestParser</code>,
214 <code class="literal">XMLUnit.getControlDocumentBuilderFactory</code>,
215 <code class="literal">XMLUnit.getTestDocumentBuilderFactory</code> and
216 <code class="literal">XMLUnit.getSAXParserFactory</code> (used by
217 <code class="literal">Validator</code>). Note that all these methods
218 return factories or parsers that are namespace aware.</p>
219
220 <p>The various <code class="literal">build...</code> methods in
221 <code class="literal">XMLUnit</code> provide convenience layers for
222 building DOM <code class="literal">Document</code>s using the configured
223 parsers.</p>
224
225 <p>You can also set the class name for the
226 <code class="literal">XPathFactory</code> to use when using JAXP 1.3 by
227 passing the class name to
228 <code class="literal">XMLUnit.setXPathFactory</code>.</p>
229
230 </div>
231
232 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="EntityResolver"></a>2.4.2. <code class="literal">EntityResolver</code></h4></div></div></div>
233
234
235 <p>You can provide a custom
236 <code class="literal">org.xml.sax.EntityResolver</code> for the control
237 and test parsers via
238 <code class="literal">XMLUnit.setControlEntityResolver</code> and
239 <code class="literal">XMLUnit.setTestEntityResolver</code>.
240 <code class="literal">Validator</code> uses the resolver set via
241 <code class="literal">setControlEntityResolver</code> as well.</p>
242 </div>
243
244 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Basic:%20Element%20Content%20Whitespace"></a>2.4.3. Element Content Whitespace</h4></div></div></div>
245
246
247 <p>Element content whitespace - also known as ignorable
248 whitespace - is whitespace contained in elements whose content
249 model doesn't allow text content. I.e. the newline and space
250 characters between <code class="literal">&lt;foo&gt;</code> and
251 <code class="literal">&lt;bar&gt;</code> in the following example
252 could belong into this category.</p>
253
254 <pre class="programlisting">
255 &lt;foo&gt;
256 &lt;bar/&gt;&lt;/foo&gt;
257 </pre>
258
259 <p>Using <code class="literal">XMLUnit.setIgnoreWhitespace</code> it
260 is possible to make the test and control parser ignore this
261 kind of whitespace.</p>
262
263 <p>Note that setting this property to
264 <code class="literal">true</code> usually doesn't have any effect since
265 it only works on validating parsers and XMLUnit doesn't enable
266 validation by default. It does have an effect when comparing
267 pieces of XML, though, since the same flag is used for a
268 different purpose as well in that case. See <a class="xref" href="ar01s03.html#Whitespace%20Handling" title="3.8.1. Whitespace Handling">Section 3.8.1, &#8220;Whitespace Handling&#8221;</a> for more details.</p>
269
270 </div>
271
272 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="XSLT%20Stylesheet%20Version"></a>2.4.4. XSLT Stylesheet Version</h4></div></div></div>
273
274
275 <p>Some features of XMLUnit use XSLT stylesheets under the
276 covers, in particular XSLT will be used to strip element
277 content whitespace or comments as well as by
278 <code class="literal">SimpleXpathEngine</code>. These stylesheets only
279 require a XSLT transformer that supports XSLT 1.0 and will say
280 so in the <code class="literal">stylesheet</code> element.</p>
281
282 <p>If your XSLT transformer supports XSLT 2.0 or newer it
283 may<a href="#ftn.idp42609744" class="footnote" name="idp42609744"><sup class="footnote">[6]</sup></a> issue a warning for these stylesheets
284 which can be annoying. You can use
285 <code class="literal">XMLUnit.setXSLTVersion</code> to make XMLUnit
286 change the version attribute to a different value. Note that
287 XMLUnit hasn't been tested with a value other than
288 <code class="literal">"1.0"</code>.</p>
289 </div>
290 </div>
291
292 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Providing%20Input%20to%20XMLUnit"></a>2.5. Providing Input to XMLUnit</h3></div></div></div>
293
294
295 <p>Most methods in XMLUnit that expect a piece of XML as
296 input provide several overloads that obtain their input from
297 different sources. The most common options are:</p>
298
299 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">A DOM <code class="literal">Document</code>.
300
301 <p>Here you have all control over the document's
302 creation. Such a <code class="literal">Document</code> could as well
303 be the result of an XSLT transformation via the
304 <code class="literal">Transform</code> class.</p>
305 </li><li class="listitem">A SAX <code class="literal">InputSource</code>.
306
307 <p>This is the most generic way since
308 <code class="literal">InputSource</code> allows you to read from
309 arbitrary <code class="literal">InputStream</code>s or
310 <code class="literal">Reader</code>s. Use an
311 <code class="literal">InputStream</code> wrapped by an
312 <code class="literal">InputSource</code> if you want the XML parser to
313 pick up the proper encoding from the XML declaration.</p>
314 </li><li class="listitem">A <code class="literal">String</code>.
315
316 <p>Here a DOM <code class="literal">Document</code> is built from
317 the input <code class="literal">String</code> using the JAXP parser
318 specified for control or test documents - depending on
319 whether the input is a control or test piece of XML.</p>
320
321 <p>Note that using a <code class="literal">String</code> assumes
322 that your XML has already been converted from its XML
323 encoding to a Java <code class="literal">String</code> upfront.</p>
324 </li><li class="listitem">A <code class="literal">Reader</code>.
325
326 <p>Here a DOM <code class="literal">Document</code> is built from
327 the input <code class="literal">Reader</code> using the JAXP parser
328 specified for control or test documents - depending on
329 whether the input is a control or test piece of XML.</p>
330
331 <p>Note that using a <code class="literal">Reader</code> is a
332 bad choice if your XML encoding is different from your
333 platform's default encoding since Java's IO system won't
334 read your XML declaration. It is a good practice to use one
335 of the other overloads rather than the
336 <code class="literal">Reader</code> version to ensure encoding has
337 been dealt with properly.</p>
338 </li></ul></div>
339 </div>
340
341 <div class="footnotes"><br><hr style="width:100; text-align:left;margin-left: 0"><div id="ftn.idp42609744" class="footnote"><p><a href="#idp42609744" class="para"><sup class="para">[6] </sup></a>The W3C recommendation says it
342 SHOULD.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">XMLUnit Java User's Guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 3. Comparing Pieces of XML</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>3. Comparing Pieces of XML</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s02.html" title="2. Using XMLUnit"><link rel="next" href="ar01s04.html" title="4. Validating XML Documents"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3. Comparing Pieces of XML</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Comparing%20Pieces%20of%20XML"></a>3. Comparing Pieces of XML</h2></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="The%20Difference%20Engine"></a>3.1. The Difference Engine</h3></div></div></div>
4
5
6 <p>At the center of XMLUnit's support for comparisons is the
7 <code class="literal">DifferenceEngine</code> class. In practice you
8 rarely deal with it directly but rather use it via instances of
9 <code class="literal">Diff</code> or <code class="literal">DetailedDiff</code>
10 classes (see <a class="xref" href="ar01s03.html#Diff" title="3.5. Diff and DetailedDiff">Section 3.5, &#8220;<code class="literal">Diff</code> and
11 <code class="literal">DetailedDiff</code>&#8221;</a>).</p>
12
13 <p>The <code class="literal">DifferenceEngine</code> walks two trees of
14 DOM <code class="literal">Node</code>s, the control and the test tree, and
15 compares the nodes. Whenever it detects a difference, it sends
16 a message to a configured <code class="literal">DifferenceListener</code>
17 (see <a class="xref" href="ar01s03.html#DifferenceListener" title="3.3. DifferenceListener">Section 3.3, &#8220;<code class="literal">DifferenceListener</code>&#8221;</a>) and asks a
18 <code class="literal">ComparisonController</code> (see <a class="xref" href="ar01s03.html#ComparisonController" title="3.2. ComparisonController">Section 3.2, &#8220;<code class="literal">ComparisonController</code>&#8221;</a>) whether the current comparison
19 should be halted.</p>
20
21 <p>In some cases the order of elements in two pieces of XML
22 may not be significant. If this is true, the
23 <code class="literal">DifferenceEngine</code> needs help to determine
24 which <code class="literal">Element</code>s to compare. This is the job
25 of an <code class="literal">ElementQualifier</code> (see <a class="xref" href="ar01s03.html#ElementQualifier" title="3.4. ElementQualifier">Section 3.4, &#8220;<code class="literal">ElementQualifier</code>&#8221;</a>).</p>
26
27 <p>The types of differences
28 <code class="literal">DifferenceEngine</code> can detect are enumerated in
29 the <code class="literal">DifferenceConstants</code> interface and
30 represented by instances of the <code class="literal">Difference</code>
31 class.</p>
32
33 <p>A <code class="literal">Difference</code> can be recoverable;
34 recoverable <code class="literal">Difference</code>s make the
35 <code class="literal">Diff</code> class consider two pieces of XML similar
36 while non-recoverable <code class="literal">Difference</code>s render the
37 two pieces different.</p>
38
39 <p>The types of <code class="literal">Difference</code>s that are
40 currently detected are listed in <a class="xref" href="ar01s03.html#docleveldiff" title="Table 1. Document level Differences detected by DifferenceEngine">Table 1, &#8220;Document level <code class="literal">Difference</code>s detected by
41 <code class="literal">DifferenceEngine</code>&#8221;</a>
42 to <a class="xref" href="ar01s03.html#otherdiff" title="Table 4. Other Differences detected by DifferenceEngine">Table 4, &#8220;Other <code class="literal">Difference</code>s detected by
43 <code class="literal">DifferenceEngine</code>&#8221;</a> (the first two columns refer to
44 the <code class="literal">DifferenceConstants</code> class).</p>
45
46 <div class="table"><a name="docleveldiff"></a><p class="title"><b>Table 1. Document level <code class="literal">Difference</code>s detected by
47 <code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
48
49 <table summary="Document level Differences detected by
50 DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION_ID</code></td><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">One piece of XML has a DOCTYPE declaration while
51 the other one has not.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_NAME_ID</code></td><td align="center"><code class="literal">DOCTYPE_NAME</code></td><td align="center"><code class="literal">false</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
52 but the declarations specify different names for the
53 root element.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID_ID</code></td><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID</code></td><td align="center"><code class="literal">false</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
54 but the declarations specify different PUBLIC
55 identifiers.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID_ID</code></td><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID</code></td><td align="center"><code class="literal">true</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
56 but the declarations specify different SYSTEM
57 identifiers.</td></tr><tr><td align="center"><code class="literal">NODE_TYPE_ID</code></td><td align="center"><code class="literal">NODE_TYPE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The test piece of XML contains a different type
58 of node than was expected. This type of difference will
59 also occur if either the root control or test
60 <code class="literal">Node</code> is <code class="literal">null</code> while
61 the other is not.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_PREFIX_ID</code></td><td align="center"><code class="literal">NAMESPACE_PREFIX</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes use different prefixes for the same
62 XML Namespace URI in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_URI_ID</code></td><td align="center"><code class="literal">NAMESPACE_URI</code></td><td align="center"><code class="literal">false</code></td><td align="left">Two nodes in the two pieces of XML share the same
63 local name but use different XML Namespace URIs.</td></tr><tr><td align="center"><code class="literal">SCHEMA_LOCATION_ID</code></td><td align="center"><code class="literal">SCHEMA_LOCATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes have different values for the
64 <code class="literal">schemaLocation</code> attribute of the
65 XMLSchema-Instance namespace. The attribute could be
66 present on only one of the two nodes.</td></tr><tr><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION_ID</code></td><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes have different values for the
67 <code class="literal">noNamespaceSchemaLocation</code> attribute
68 of the XMLSchema-Instance namespace. The attribute
69 could be present on only one of the two nodes.</td></tr></tbody></table>
70 </div></div><br class="table-break">
71
72 <div class="table"><a name="elementleveldiff"></a><p class="title"><b>Table 2. Element level <code class="literal">Difference</code>s detected by
73 <code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
74
75 <table summary="Element level Differences detected by
76 DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">ELEMENT_TAG_NAME_ID</code></td><td align="center"><code class="literal">ELEMENT_TAG_NAME</code></td><td align="center"><code class="literal">false</code></td><td align="left">The two pieces of XML contain elements with
77 different tag names.</td></tr><tr><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES_ID</code></td><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES</code></td><td align="center"><code class="literal">false</code></td><td align="left">The two pieces of XML contain a common element,
78 but the number of attributes on the element is
79 different.</td></tr><tr><td align="center"><code class="literal">HAS_CHILD_NODES_ID</code></td><td align="center"><code class="literal">HAS_CHILD_NODES</code></td><td align="center"><code class="literal">false</code></td><td align="left">An element in one piece of XML has child nodes
80 while the corresponding one in the other has not.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_LENGTH_ID</code></td><td align="center"><code class="literal">CHILD_NODELIST_LENGTH</code></td><td align="center"><code class="literal">false</code></td><td align="left">Two elements in the two pieces of XML differ by
81 their number of child nodes.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE_ID</code></td><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two elements in the two pieces of XML contain the
82 same child nodes but in a different order.</td></tr><tr><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND_ID</code></td><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND</code></td><td align="center"><code class="literal">false</code></td><td align="left">A child node in one piece of XML couldn't be
83 matched against any other node of the other piece.</td></tr><tr><td align="center"><code class="literal">ATTR_SEQUENCE_ID</code></td><td align="center"><code class="literal">ATTR_SEQUENCE</code></td><td align="center"><code class="literal">true</code></td><td align="left">The attributes on an element appear in different
84 order<a href="#ftn.idp42740768" class="footnote" name="idp42740768"><sup class="footnote">[a]</sup></a> in the two pieces of
85 XML.</td></tr></tbody><tbody class="footnotes"><tr><td colspan="4"><div id="ftn.idp42740768" class="footnote"><p><a href="#idp42740768" class="para"><sup class="para">[a] </sup></a>Note that the order of attributes
86 is not significant in XML, different parsers may return
87 attributes in a different order even if parsing the same
88 XML document. There is an option to turn this check off
89 - see <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8. Configuration Options">Section 3.8, &#8220;Configuration Options&#8221;</a> - but it is on
90 by default for backwards compatibility
91 reasons</p></div></td></tr></tbody></table>
92 </div></div><br class="table-break">
93
94 <div class="table"><a name="attributeleveldiff"></a><p class="title"><b>Table 3. Attribute level <code class="literal">Difference</code>s detected by
95 <code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
96
97
98 <table summary="Attribute level Differences detected by
99 DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</code></td><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED</code></td><td align="center"><code class="literal">true</code></td><td align="left">An attribute that has a default value according
100 to the content model of the element in question has been
101 specified explicitly in one piece of XML but not in the
102 other.<a href="#ftn.idp42757728" class="footnote" name="idp42757728"><sup class="footnote">[a]</sup></a></td></tr><tr><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND_ID</code></td><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND</code></td><td align="center"><code class="literal">false</code></td><td align="left">One piece of XML contains an attribute on an
103 element that is missing in the other.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_ID</code></td><td align="center"><code class="literal">ATTR_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The value of an element's attribute is different
104 in the two pieces of XML.</td></tr></tbody><tbody class="footnotes"><tr><td colspan="4"><div id="ftn.idp42757728" class="footnote"><p><a href="#idp42757728" class="para"><sup class="para">[a] </sup></a>In order for this difference to be
105 detected the parser must have been in validating mode
106 when the piece of XML was parsed and the DTD or XML
107 Schema must have been available.</p></div></td></tr></tbody></table>
108 </div></div><br class="table-break">
109
110 <div class="table"><a name="otherdiff"></a><p class="title"><b>Table 4. Other <code class="literal">Difference</code>s detected by
111 <code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
112
113
114 <table summary="Other Differences detected by
115 DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">COMMENT_VALUE_ID</code></td><td align="center"><code class="literal">COMMENT_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The content of two comments is different in the
116 two pieces of XML.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET_ID</code></td><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET</code></td><td align="center"><code class="literal">false</code></td><td align="left">The target of two processing instructions is
117 different in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA_ID</code></td><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA</code></td><td align="center"><code class="literal">false</code></td><td align="left">The data of two processing instructions is
118 different in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">CDATA_VALUE_ID</code></td><td align="center"><code class="literal">CDATA_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The content of two CDATA sections is different in
119 the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">TEXT_VALUE_ID</code></td><td align="center"><code class="literal">TEXT_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The value of two texts is different in the two
120 pieces of XML.</td></tr></tbody></table>
121 </div></div><br class="table-break">
122
123 <p>Note that some of the differences listed may be ignored by
124 the <code class="literal">DifferenceEngine</code> if certain configuration
125 options have been specified. See <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8. Configuration Options">Section 3.8, &#8220;Configuration Options&#8221;</a> for details.</p>
126
127 <p><code class="literal">DifferenceEngine</code> passes differences
128 found around as instances of the <code class="literal">Difference</code>
129 class. In addition to the type of of difference this class also
130 holds information on the nodes that have been found to be
131 different. The nodes are described by
132 <code class="literal">NodeDetail</code> instances that encapsulate the DOM
133 <code class="literal">Node</code> instance as well as the XPath expression
134 that locates the <code class="literal">Node</code> inside the given piece
135 of XML. <code class="literal">NodeDetail</code> also contains a "value"
136 that provides more information on the actual values that have
137 been found to be different, the concrete interpretation depends
138 on the type of difference as can be seen in <a class="xref" href="ar01s03.html#diffvalue" title="Table 5. Contents of NodeDetail.getValue() for Differences">Table 5, &#8220;Contents of <code class="literal">NodeDetail.getValue()</code>
139 for <code class="literal">Difference</code>s&#8221;</a>.</p>
140
141 <div class="table"><a name="diffvalue"></a><p class="title"><b>Table 5. Contents of <code class="literal">NodeDetail.getValue()</code>
142 for <code class="literal">Difference</code>s</b></p><div class="table-contents">
143
144
145 <table summary="Contents of NodeDetail.getValue()
146 for Differences" border="1"><colgroup><col align="center" class="id"><col align="left" class="value"></colgroup><thead><tr><th align="center"><code class="literal">Difference.getId()</code></th><th align="center"><code class="literal">NodeDetail.getValue()</code></th></tr></thead><tbody><tr><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION_ID</code></td><td align="left"><code class="literal">"not null"</code> if the document has
147 a DOCTYPE declaration, <code class="literal">"null"</code>
148 otherwise.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_NAME_ID</code></td><td align="left">The name of the root element.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID</code></td><td align="left">The PUBLIC identifier.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID</code></td><td align="left">The SYSTEM identifier.</td></tr><tr><td align="center"><code class="literal">NODE_TYPE_ID</code></td><td align="left">If one node was absent: <code class="literal">"not
149 null"</code> if the node exists,
150 <code class="literal">"null"</code> otherwise. If the node types
151 differ the value will be a string-ified version of
152 <code class="literal">org.w3c.dom.Node.getNodeType()</code>.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_PREFIX_ID</code></td><td align="left">The Namespace prefix.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_URI_ID</code></td><td align="left">The Namespace URI.</td></tr><tr><td align="center"><code class="literal">SCHEMA_LOCATION_ID</code></td><td align="left">The attribute's value or "[attribute absent]" if
153 it has not been specified.</td></tr><tr><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION_ID</code></td><td align="left">The attribute's value or "[attribute absent]" if
154 it has not been specified.</td></tr><tr><td align="center"><code class="literal">ELEMENT_TAG_NAME_ID</code></td><td align="left">The tag name with any Namespace information
155 stripped.</td></tr><tr><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES_ID</code></td><td align="left">The number of attributes present turned into a
156 <code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">HAS_CHILD_NODES_ID</code></td><td align="left"><code class="literal">"true"</code> if the element has
157 child nodes, <code class="literal">"false"</code>
158 otherwise.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_LENGTH_ID</code></td><td align="left">The number of child nodes present turned into a
159 <code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE_ID</code></td><td align="left">The sequence number of this child node turned into a
160 <code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND_ID</code></td><td align="left">The name of the unmatched node or
161 <code class="literal">"null"</code>. If the node is an element
162 inside an XML namespace the name will be
163 Java5-<code class="literal">QName</code>-like
164 <code class="literal">{NS-URI}LOCAL-NAME</code> - in all other
165 cases it is the node's local name.</td></tr><tr><td align="center"><code class="literal">ATTR_SEQUENCE_ID</code></td><td align="left">The attribute's name.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</code></td><td align="left"><code class="literal">"true"</code> if the attribute has
166 been specified, <code class="literal">"false"</code>
167 otherwise.</td></tr><tr><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND_ID</code></td><td align="left">The attribute's name or
168 <code class="literal">"null"</code>. If the attribute belongs to
169 an XML namespace the name will be
170 Java5-<code class="literal">QName</code>-like
171 <code class="literal">{NS-URI}LOCAL-NAME</code> - in all other
172 cases it is the attribute's local name.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_ID</code></td><td align="left">The attribute's value.</td></tr><tr><td align="center"><code class="literal">COMMENT_VALUE_ID</code></td><td align="left">The actual comment.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET_ID</code></td><td align="left">The processing instruction's target.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA_ID</code></td><td align="left">The processing instruction's data.</td></tr><tr><td align="center"><code class="literal">CDATA_VALUE_ID</code></td><td align="left">The content of the CDATA section.</td></tr><tr><td align="center"><code class="literal">TEXT_VALUE_ID</code></td><td align="left">The actual text.</td></tr></tbody></table>
173 </div></div><br class="table-break">
174
175 <p>As said in the first paragraph you won't deal with
176 <code class="literal">DifferenceEngine</code> directly in most cases. In
177 cases where <code class="literal">Diff</code> or
178 <code class="literal">DetailedDiff</code> don't provide what you need
179 you'd create an instance of <code class="literal">DifferenceEngine</code>
180 passing a <code class="literal">ComparisonController</code> in the
181 constructor and invoke <code class="literal">compare</code> with your DOM
182 trees to compare as well as a
183 <code class="literal">DifferenceListener</code> and
184 <code class="literal">ElementQualifier</code>. The listener will be
185 called on any differences while the <code class="literal">control</code>
186 method is executing.</p>
187
188 <div class="example"><a name="idp42875088"></a><p class="title"><b>Example 16. Using <code class="literal">DifferenceEngine</code>
189 Directly</b></p><div class="example-contents">
190
191 <pre class="programlisting">
192 class MyDifferenceListener implements DifferenceListener {
193 private boolean calledFlag = false;
194 public boolean called() { return calledFlag; }
195
196 public int differenceFound(Difference difference) {
197 calledFlag = true;
198 return RETURN_ACCEPT_DIFFERENCE;
199 }
200
201 public void skippedComparison(Node control, Node test) {
202 }
203 }
204
205 DifferenceEngine engine = new DifferenceEngine(myComparisonController);
206 MyDifferenceListener listener = new MyDifferenceListener();
207 engine.compare(controlNode, testNode, listener,
208 myElementQualifier);
209 System.err.println("There have been "
210 + (listener.called() ? "" : "no ")
211 + "differences.");
212 </pre></div></div><br class="example-break">
213 </div>
214
215 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="ComparisonController"></a>3.2. <code class="literal">ComparisonController</code></h3></div></div></div>
216
217
218 <p>The <code class="literal">ComparisonController</code>'s job is to
219 decide whether a comparison should be halted after a difference
220 has been found. Its interface is:</p>
221
222 <pre class="programlisting">
223 /**
224 * Determine whether a Difference that the listener has been notified of
225 * should halt further XML comparison. Default behaviour for a Diff
226 * instance is to halt if the Difference is not recoverable.
227 * @see Difference#isRecoverable
228 * @param afterDifference the last Difference passed to &lt;code&gt;differenceFound&lt;/code&gt;
229 * @return true to halt further comparison, false otherwise
230 */
231 boolean haltComparison(Difference afterDifference);
232 </pre>
233
234 <p>Whenever a difference has been detected by the
235 <code class="literal">DifferenceEngine</code> the
236 <code class="literal">haltComparison</code> method will be called
237 immediately after the <code class="literal">DifferenceListener</code> has
238 been informed of the difference. This is true no matter what
239 type of <code class="literal">Difference</code> has been found or which
240 value the <code class="literal">DifferenceListener</code> has
241 returned.</p>
242
243 <p>The only implementations of
244 <code class="literal">ComparisonController</code> that ship with XMLUnit
245 are <code class="literal">Diff</code> and <code class="literal">DetailedDiff</code>,
246 see <a class="xref" href="ar01s03.html#Diff" title="3.5. Diff and DetailedDiff">Section 3.5, &#8220;<code class="literal">Diff</code> and
247 <code class="literal">DetailedDiff</code>&#8221;</a> for details about them.</p>
248
249 <p>A <code class="literal">ComparisonController</code> that halted the
250 comparison on any non-recoverable difference could be
251 implemented as:</p>
252
253 <div class="example"><a name="idp42890832"></a><p class="title"><b>Example 17. A Simple
254 <code class="literal">ComparisonController</code></b></p><div class="example-contents">
255
256 <pre class="programlisting">
257 public class HaltOnNonRecoverable implements ComparisonController {
258 public boolean haltComparison(Difference afterDifference) {
259 return !afterDifference.isRecoverable();
260 }
261 }
262 </pre></div></div><br class="example-break">
263 </div>
264
265 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DifferenceListener"></a>3.3. <code class="literal">DifferenceListener</code></h3></div></div></div>
266
267
268 <p><code class="literal">DifferenceListener</code> contains two
269 callback methods that are invoked by the
270 <code class="literal">DifferenceEngine</code> when differences are
271 detected:</p>
272
273 <pre class="programlisting">
274 /**
275 * Receive notification that 2 nodes are different.
276 * @param difference a Difference instance as defined in {@link
277 * DifferenceConstants DifferenceConstants} describing the cause
278 * of the difference and containing the detail of the nodes that
279 * differ
280 * @return int one of the RETURN_... constants describing how this
281 * difference was interpreted
282 */
283 int differenceFound(Difference difference);
284
285 /**
286 * Receive notification that a comparison between 2 nodes has been skipped
287 * because the node types are not comparable by the DifferenceEngine
288 * @param control the control node being compared
289 * @param test the test node being compared
290 * @see DifferenceEngine
291 */
292 void skippedComparison(Node control, Node test);
293 </pre>
294
295 <p><code class="literal">differenceFound</code> is invoked by
296 <code class="literal">DifferenceEngine</code> as soon as a difference has
297 been detected. The return value of that method is completely
298 ignored by <code class="literal">DifferenceEngine</code>, it becomes
299 important when used together with <code class="literal">Diff</code>,
300 though (see <a class="xref" href="ar01s03.html#Diff" title="3.5. Diff and DetailedDiff">Section 3.5, &#8220;<code class="literal">Diff</code> and
301 <code class="literal">DetailedDiff</code>&#8221;</a>). The return value should be
302 one of the four constants defined in the the
303 <code class="literal">DifferenceListener</code> interface:</p>
304
305 <pre class="programlisting">
306 /**
307 * Standard return value for the &lt;code&gt;differenceFound&lt;/code&gt; method.
308 * Indicates that the &lt;code&gt;Difference&lt;/code&gt; is interpreted as defined
309 * in {@link DifferenceConstants DifferenceConstants}.
310 */
311 int RETURN_ACCEPT_DIFFERENCE;
312 /**
313 * Override return value for the &lt;code&gt;differenceFound&lt;/code&gt; method.
314 * Indicates that the nodes identified as being different should be
315 * interpreted as being identical.
316 */
317 int RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
318 /**
319 * Override return value for the &lt;code&gt;differenceFound&lt;/code&gt; method.
320 * Indicates that the nodes identified as being different should be
321 * interpreted as being similar.
322 */
323 int RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
324 /**
325 * Override return value for the &lt;code&gt;differenceFound&lt;/code&gt; method.
326 * Indicates that the nodes identified as being similar should be
327 * interpreted as being different.
328 */
329 int RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT = 3;
330 </pre>
331
332 <p>The <code class="literal">skippedComparison</code> method is
333 invoked if the <code class="literal">DifferenceEngine</code> encounters
334 two <code class="literal">Node</code>s it cannot compare. Before invoking
335 <code class="literal">skippedComparison</code>
336 <code class="literal">DifferenceEngine</code> will have invoked
337 <code class="literal">differenceFound</code> with a
338 <code class="literal">Difference</code> of type
339 <code class="literal">NODE_TYPE</code>.</p>
340
341 <p>A custom <code class="literal">DifferenceListener</code> that
342 ignored any DOCTYPE related differences could be written
343 as:</p>
344
345 <div class="example"><a name="idp42913264"></a><p class="title"><b>Example 18. A <code class="literal">DifferenceListener</code> that Ignores
346 DOCTYPE Differences</b></p><div class="example-contents">
347
348 <pre class="programlisting">
349 public class IgnoreDoctype implements DifferenceListener {
350 private static final int[] IGNORE = new int[] {
351 DifferenceConstants.HAS_DOCTYPE_DECLARATION_ID,
352 DifferenceConstants.DOCTYPE_NAME_ID,
353 DifferenceConstants.DOCTYPE_PUBLIC_ID_ID,
354 DifferenceConstants.DOCTYPE_SYSTEM_ID_ID
355 };
356
357 static {
358 Arrays.sort(IGNORE);
359 }
360
361 public int differenceFound(Difference difference) {
362 return Arrays.binarySearch(IGNORE, difference.getId()) &gt;= 0
363 ? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
364 : RETURN_ACCEPT_DIFFERENCE;
365 }
366
367 public void skippedComparison(Node control, Node test) {
368 }
369 }
370 </pre></div></div><br class="example-break">
371
372 <p>Apart from <code class="literal">Diff</code> and
373 <code class="literal">DetailedDiff</code> XMLUnit ships with an additional
374 implementation of <code class="literal">DifferenceListener</code>.</p>
375
376 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="IgnoreTextAndAttributeValuesDifferenceListener"></a>3.3.1. <code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code></h4></div></div></div>
377
378
379 <p><code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code>
380 doesn't do anything in <code class="literal">skippedComparison</code>.
381 It "downgrades" <code class="literal">Difference</code>s of type
382 <code class="literal">ATTR_VALUE</code>,
383 <code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED</code> and
384 <code class="literal">TEXT_VALUE</code> to recoverable
385 differences.</p>
386
387 <p>This means if instances of
388 <code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code>
389 are used together with <code class="literal">Diff</code> then two pieces
390 of XML will be considered similar if they have the same basic
391 structure. They are not considered identical, though.</p>
392
393 <p>Note that the list of ignored differences doesn't cover
394 all textual differences. You should configure XMLUnit to
395 ignore comments and whitespace and to consider CDATA sections
396 and text nodes to be the same (see <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8. Configuration Options">Section 3.8, &#8220;Configuration Options&#8221;</a>) in order to cover
397 <code class="literal">COMMENT_VALUE</code> and
398 <code class="literal">CDATA_VALUE</code> as well.</p>
399
400 </div>
401 </div>
402
403 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="ElementQualifier"></a>3.4. <code class="literal">ElementQualifier</code></h3></div></div></div>
404
405
406 <p>When <code class="literal">DifferenceEngine</code> encounters a list
407 of DOM <code class="literal">Element</code>s as children of another
408 <code class="literal">Element</code> it will ask the configured
409 <code class="literal">ElementQualifier</code> which
410 <code class="literal">Element</code> of the control piece of XML should be
411 compared to which of the test piece. Its contract is:</p>
412
413 <pre class="programlisting">
414 /**
415 * Determine whether two elements are comparable
416 * @param control an Element from the control XML NodeList
417 * @param test an Element from the test XML NodeList
418 * @return true if the elements are comparable, false otherwise
419 */
420 boolean qualifyForComparison(Element control, Element test);
421 </pre>
422
423 <p>For any given <code class="literal">Element</code> in the control
424 piece of XML <code class="literal">DifferenceEngine</code> will cycle
425 through the corresponding list of <code class="literal">Element</code>s in
426 the test piece of XML until
427 <code class="literal">qualifyForComparison</code> has returned
428 <code class="literal">true</code> or the test document is
429 exhausted.</p>
430
431 <p>When using <code class="literal">DifferenceEngine</code> or
432 <code class="literal">Diff</code> it is completely legal to set the
433 <code class="literal">ElementQualifier</code> to <code class="literal">null</code>.
434 In this case any kind of <code class="literal">Node</code> is compared to
435 the test <code class="literal">Node</code> that appears at the same
436 position in the sequence.</p>
437
438 <div class="example"><a name="eq-nodelist-example"></a><p class="title"><b>Example 19. Example Nodes for <code class="literal">ElementQualifier</code>
439 (the comments are not part of the example)</b></p><div class="example-contents">
440
441 <pre class="programlisting">
442 &lt;!-- control piece of XML --&gt;
443 &lt;parent&gt;
444 &lt;child1/&gt; &lt;!-- control node 1 --&gt;
445 &lt;child2/&gt; &lt;!-- control node 2 --&gt;
446 &lt;child2 foo="bar"&gt;xyzzy&lt;/child2&gt; &lt;!-- control node 3 --&gt;
447 &lt;child2 foo="baz"/&gt; &lt;!-- control node 4 --&gt;
448 &lt;/parent&gt;
449
450 &lt;!-- test piece of XML --&gt;
451 &lt;parent&gt;
452 &lt;child2 foo="baz"/&gt; &lt;!-- test node 1 --&gt;
453 &lt;child1/&gt; &lt;!-- test node 2 --&gt;
454 &lt;child2&gt;xyzzy&lt;/child2&gt; &lt;!-- test node 3 --&gt;
455 &lt;child2 foo="bar"/&gt; &lt;!-- test node 4 --&gt;
456 &lt;/parent&gt;
457 </pre></div></div><br class="example-break">
458
459 <p>Taking <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example 19. Example Nodes for ElementQualifier (the comments are not part of the example)">Example 19, &#8220;Example Nodes for <code class="literal">ElementQualifier</code>
460 (the comments are not part of the example)&#8221;</a> without any
461 <code class="literal">ElementQualifier</code>
462 <code class="literal">DifferenceEngine</code> will compare control node
463 <code class="literal">n</code> to test node <code class="literal">n</code> for
464 <code class="literal">n</code> between 1 and 4. In many cases this is
465 exactly what is desired, but sometimes
466 <code class="literal">&lt;a&gt;&lt;b/&gt;&lt;c/&gt;&lt;/a&gt;</code> should be similar
467 to <code class="literal">&lt;a&gt;&lt;c/&gt;&lt;b/&gt;&lt;/a&gt;</code> because the
468 order of elements doesn't matter - this is when you'd use a
469 different <code class="literal">ElementQualifier</code>. XMLUnit ships
470 with several implementations.</p>
471
472 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameQualifier"></a>3.4.1. <code class="literal">ElementNameQualifier</code></h4></div></div></div>
473
474
475 <p>Only <code class="literal">Element</code>s with the same name -
476 and Namespace URI if present - qualify.</p>
477
478 <p>In <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example 19. Example Nodes for ElementQualifier (the comments are not part of the example)">Example 19, &#8220;Example Nodes for <code class="literal">ElementQualifier</code>
479 (the comments are not part of the example)&#8221;</a> this means
480 control node 1 will be compared to test node 2. Then control
481 node 2 will be compared to test node 3 because
482 <code class="literal">DifferenceEngine</code> will start to search for
483 the matching test <code class="literal">Element</code> at the second
484 test node, the same sequence number the control node is at.
485 Control node 3 is compared to test node 3 as well and control
486 node 4 to test node 4.</p>
487 </div>
488
489 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameAndAttributeQualifier"></a>3.4.2. <code class="literal">ElementNameAndAttributeQualifier</code></h4></div></div></div>
490
491
492 <p>Only <code class="literal">Element</code>s with the same name -
493 and Namespace URI if present - as well as the same values for
494 all attributes given in
495 <code class="literal">ElementNameAndAttributeQualifier</code>'s
496 constructor qualify.</p>
497
498 <p>Let's say <code class="literal">"foo"</code> has been passed to
499 <code class="literal">ElementNameAndAttributeQualifier</code>'s
500 constructor when looking at <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example 19. Example Nodes for ElementQualifier (the comments are not part of the example)">Example 19, &#8220;Example Nodes for <code class="literal">ElementQualifier</code>
501 (the comments are not part of the example)&#8221;</a>. This again means control
502 node 1 will be compared to test node 2 since they do have the
503 same name and no value at all for attribute
504 <code class="literal">"foo"</code>. Then control node 2 will be
505 compared to test node 3 - again, no value for
506 <code class="literal">"foo"</code>. Control node 3 is compared to test
507 node 4 as they have the same value <code class="literal">"bar"</code>.
508 Finally control node 4 is compared to test node 1; here
509 <code class="literal">DifferenceEngine</code> searches from the
510 beginning of the test node list after test node 4 didn't
511 match.</p>
512
513 <p>There are three constructors in
514 <code class="literal">ElementNameAndAttributeQualifier</code>. The
515 no-arg constructor creates an instance that compares all
516 attributes while the others will compare a single attribute or
517 a given subset of all attributes.</p>
518 </div>
519
520 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameAndTextQualifier"></a>3.4.3. <code class="literal">ElementNameAndTextQualifier</code></h4></div></div></div>
521
522
523 <p>Only <code class="literal">Element</code>s with the same name -
524 and Namespace URI if present - as well as the same text
525 content nested into them qualify.</p>
526
527 <p>In <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example 19. Example Nodes for ElementQualifier (the comments are not part of the example)">Example 19, &#8220;Example Nodes for <code class="literal">ElementQualifier</code>
528 (the comments are not part of the example)&#8221;</a> this means
529 control node 1 will be compared to test node 2 since they both
530 don't have any nested text at all. Then control node 2 will
531 be compared to test node 4. Control node 3 is compared to
532 test node 3 since they have the same nested text and control
533 node 4 to test node 4.</p>
534 </div>
535
536 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="RecursiveElementNameAndTextQualifier"></a>3.4.4. <code class="literal">org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</code></h4></div></div></div>
537
538
539 <p>All <code class="literal">ElementQualifier</code>s seen so far
540 only looked at the <code class="literal">Element</code>s themselves and
541 not at the structure nested into them at a deeper level. A
542 frequent user question has been which
543 <code class="literal">ElementQualifier</code> should be used if the
544 pieces of XML in <a class="xref" href="ar01s03.html#htmltable" title="Example 20. Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example 20, &#8220;Example for
545 <code class="literal">RecursiveElementNameAndTextQualifier</code>
546 (the comments are not part of the example)&#8221;</a> should be
547 considered similar.</p>
548
549 <div class="example"><a name="htmltable"></a><p class="title"><b>Example 20. Example for
550 <code class="literal">RecursiveElementNameAndTextQualifier</code>
551 (the comments are not part of the example)</b></p><div class="example-contents">
552
553 <pre class="programlisting">
554 &lt;!-- control --&gt;
555 &lt;table&gt;
556 &lt;tr&gt; &lt;!-- control row 1 --&gt;
557 &lt;td&gt;foo&lt;/td&gt;
558 &lt;/tr&gt;
559 &lt;tr&gt; &lt;!-- control row 2 --&gt;
560 &lt;td&gt;bar&lt;/td&gt;
561 &lt;/tr&gt;
562 &lt;/table&gt;
563
564 &lt;!-- test --&gt;
565 &lt;table&gt;
566 &lt;tr&gt; &lt;!-- test row 1 --&gt;
567 &lt;td&gt;bar&lt;/td&gt;
568 &lt;/tr&gt;
569 &lt;tr&gt; &lt;!-- test row 2 --&gt;
570 &lt;td&gt;foo&lt;/td&gt;
571 &lt;/tr&gt;
572 &lt;/table&gt;
573 </pre></div></div><br class="example-break">
574
575 <p>At first glance
576 <code class="literal">ElementNameAndTextQualifier</code> should work but
577 it doesn't. When <code class="literal">DifferenceEngine</code>
578 processed the children of <code class="literal">table</code> it would
579 compare control row 1 to test row 1 since both
580 <code class="literal">tr</code> elements have the same name and both
581 have no textual content at all.</p>
582
583 <p>What is needed in this case is an
584 <code class="literal">ElementQualifier</code> that looks at the element's
585 name, as well as the name of the first child element and the
586 text nested into that first child element. This is what
587 <code class="literal">RecursiveElementNameAndTextQualifier</code>
588 does.</p>
589
590 <p><code class="literal">RecursiveElementNameAndTextQualifier</code>
591 ignores whitespace between the elements leading up to the
592 nested text.</p>
593 </div>
594
595 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="MultiLevelElementNameAndTextQualifier"></a>3.4.5. <code class="literal">org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier</code></h4></div></div></div>
596
597
598 <p>
599 <code class="literal">MultiLevelElementNameAndTextQualifier</code> has
600 in a way been the predecessor
601 of <a class="xref" href="ar01s03.html#RecursiveElementNameAndTextQualifier" title="3.4.4. org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier">Section 3.4.4, &#8220;<code class="literal">org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</code>&#8221;</a>.
602 It also matches element names and those of nested child
603 elements until it finds matches, but
604 unlike <code class="literal">RecursiveElementNameAndTextQualifier</code>,
605 you must
606 tell <code class="literal">MultiLevelElementNameAndTextQualifier</code>
607 at which nesting level it should expect the nested text.
608 </p>
609
610 <p>
611 <code class="literal">MultiLevelElementNameAndTextQualifier</code>'s
612 constructor expects a single argument which is the nesting
613 level of the expected text. If you use an argument of 1,
614 <code class="literal">MultiLevelElementNameAndTextQualifier</code> is
615 identical to <code class="literal">ElementNameAndTextQualifier</code>.
616 In <a class="xref" href="ar01s03.html#htmltable" title="Example 20. Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example 20, &#8220;Example for
617 <code class="literal">RecursiveElementNameAndTextQualifier</code>
618 (the comments are not part of the example)&#8221;</a> a value of 2 would be
619 needed.</p>
620
621 <p>By default
622 <code class="literal">MultiLevelElementNameAndTextQualifier</code>
623 will not ignore whitespace between the elements leading up
624 to the nested text. If your piece of XML contains this sort
625 of whitespace (like <a class="xref" href="ar01s03.html#htmltable" title="Example 20. Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example 20, &#8220;Example for
626 <code class="literal">RecursiveElementNameAndTextQualifier</code>
627 (the comments are not part of the example)&#8221;</a> which
628 contains a newline and several space characters between
629 <code class="literal">&lt;tr&gt;</code> and
630 <code class="literal">&lt;td&gt;</code>) you can either instruct
631 XMLUnit to ignore whitespace completely (see
632 <a class="xref" href="ar01s03.html#Whitespace%20Handling" title="3.8.1. Whitespace Handling">Section 3.8.1, &#8220;Whitespace Handling&#8221;</a>) or use the two-arg
633 constructor of
634 <code class="literal">MultiLevelElementNameAndTextQualifier</code>
635 introduced with XMLUnit 1.2 and set the
636 <code class="literal">ignoreEmptyTexts</code> argument to
637 true.</p>
638
639 <p>In
640 general <code class="literal">RecursiveElementNameAndTextQualifier</code>
641 requires less knowledge upfront and its whitespace-handling
642 is more intuitive.</p>
643 </div>
644
645 </div>
646
647 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Diff"></a>3.5. <code class="literal">Diff</code> and
648 <code class="literal">DetailedDiff</code></h3></div></div></div>
649
650
651 <p><code class="literal">Diff</code> and
652 <code class="literal">DetailedDiff</code> provide simplified access to
653 <code class="literal">DifferenceEngine</code> by implementing the
654 <code class="literal">ComparisonController</code> and
655 <code class="literal">DifferenceListener</code> interfaces themselves.
656 They cover the two most common use cases for comparing two
657 pieces of XML: checking whether the pieces are different (this
658 is what <code class="literal">Diff</code> does) and finding all
659 differences between them (this is what
660 <code class="literal">DetailedDiff</code> does).</p>
661
662 <p><code class="literal">DetailedDiff</code> is a subclass of
663 <code class="literal">Diff</code> and can only be constructed by creating
664 a <code class="literal">Diff</code> instance first.</p>
665
666 <p>The major difference between them is their implementation
667 of the <code class="literal">ComparisonController</code> interface:
668 <code class="literal">DetailedDiff</code> will never stop the comparison
669 since it wants to collect all differences.
670 <code class="literal">Diff</code> in turn will halt the comparison as soon
671 as the first <code class="literal">Difference</code> is found that is not
672 recoverable. In addition <code class="literal">DetailedDiff</code>
673 collects all <code class="literal">Difference</code>s in a list and
674 provides access to it.</p>
675
676 <p>By default <code class="literal">Diff</code> will consider two
677 pieces of XML as identical if no differences have been found at
678 all, similar if all differences that have been found have been
679 recoverable (see <a class="xref" href="ar01s03.html#docleveldiff" title="Table 1. Document level Differences detected by DifferenceEngine">Table 1, &#8220;Document level <code class="literal">Difference</code>s detected by
680 <code class="literal">DifferenceEngine</code>&#8221;</a> to <a class="xref" href="ar01s03.html#otherdiff" title="Table 4. Other Differences detected by DifferenceEngine">Table 4, &#8220;Other <code class="literal">Difference</code>s detected by
681 <code class="literal">DifferenceEngine</code>&#8221;</a>) and different as soon as any
682 non-recoverable difference has been found.</p>
683
684 <p>It is possible to specify a
685 <code class="literal">DifferenceListener</code> to <code class="literal">Diff</code>
686 using the <code class="literal">overrideDifferenceListener</code> method.
687 In this case each <code class="literal">Difference</code> will be
688 evaluated by the passed in
689 <code class="literal">DifferenceListener</code>. By returning
690 <code class="literal">RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL</code> the
691 custom listener can make <code class="literal">Diff</code> ignore the
692 difference completely. Likewise any
693 <code class="literal">Difference</code> for which the custom listener
694 returns
695 <code class="literal">RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR</code> will
696 be treated as if the <code class="literal">Difference</code> was
697 recoverable.</p>
698
699 <p>There are several overloads of the <code class="literal">Diff</code>
700 constructor that allow you to specify your piece of XML in many
701 ways. There are overloads that accept additional
702 <code class="literal">DifferenceEngine</code> and
703 <code class="literal">ElementQualifier</code> arguments. Passing in a
704 <code class="literal">DifferenceEngine</code> of your own is the only way
705 to use a <code class="literal">ComparisonController</code> other than
706 <code class="literal">Diff</code>.</p>
707
708 <p>Note that <code class="literal">Diff</code> and
709 <code class="literal">DetailedDiff</code> use
710 <code class="literal">ElementNameQualifier</code> as their default
711 <code class="literal">ElementQualifier</code>. This is different from
712 <code class="literal">DifferenceEngine</code> which defaults to no
713 <code class="literal">ElementQualifier</code> at all.</p>
714
715 <p>To use a custom <code class="literal">ElementQualifier</code> you
716 can also use the <code class="literal">overrideElementQualifier</code>
717 method. Use this with an argument of <code class="literal">null</code> to
718 unset the default <code class="literal">ElementQualifier</code> as
719 well.</p>
720
721 <p>To compare two pieces of XML you'd create a
722 <code class="literal">Diff</code> instance from those two pieces and
723 invoke <code class="literal">identical</code> to check that there have
724 been no differences at all and <code class="literal">similar</code> to
725 check that any difference, if any, has been recoverable. If the
726 pieces are identical they are also similar. Likewise if they
727 are not similar they can't be identical either.</p>
728
729 <div class="example"><a name="idp43049808"></a><p class="title"><b>Example 21. Comparing Two Pieces of XML Using
730 <code class="literal">Diff</code></b></p><div class="example-contents">
731
732 <pre class="programlisting">
733 Diff d = new Diff("&lt;a&gt;&lt;b/&gt;&lt;c/&gt;&lt;/a&gt;", "&lt;a&gt;&lt;c/&gt;&lt;b/&gt;&lt;/a&gt;");
734 assertFalse(d.identical()); // CHILD_NODELIST_SEQUENCE Difference
735 assertTrue(d.similar());
736 </pre></div></div><br class="example-break">
737
738 <p>The result of the comparison is cached in
739 <code class="literal">Diff</code>, repeated invocations of
740 <code class="literal">identical</code> or <code class="literal">similar</code> will
741 not reevaluate the pieces of XML.</p>
742
743 <p>Note: calling <code class="literal">toString</code> on an instance
744 of <code class="literal">Diff</code> or <code class="literal">DetailedDiff</code>
745 will perform the comparision and cache its result immediately.
746 If you change the <code class="literal">DifferenceListener</code> or
747 <code class="literal">ElementQualifier</code> after calling
748 <code class="literal">toString</code> it won't have any effect.</p>
749
750 <p><code class="literal">DetailedDiff</code> provides only a single
751 constructor that expects a <code class="literal">Diff</code> as argument.
752 Don't use <code class="literal">DetailedDiff</code> if all you need to
753 know is whether two pieces of XML are identical/similar - use
754 <code class="literal">Diff</code> directly since its short-cut
755 <code class="literal">ComparisonController</code> implementation will save
756 time in this case.</p>
757
758 <div class="example"><a name="idp43063888"></a><p class="title"><b>Example 22. Finding All Differences Using
759 <code class="literal">DetailedDiff</code></b></p><div class="example-contents">
760
761 <pre class="programlisting">
762 Diff d = new Diff("&lt;a&gt;&lt;b/&gt;&lt;c/&gt;&lt;/a&gt;", "&lt;a&gt;&lt;c/&gt;&lt;b/&gt;&lt;/a&gt;");
763 DetailedDiff dd = new DetailedDiff(d);
764 dd.overrideElementQualifier(null);
765 assertFalse(dd.similar());
766 List l = dd.getAllDifferences();
767 assertEquals(2, l.size()); // expected &lt;b/&gt; but was &lt;c/&gt; and vice versa
768 </pre></div></div><br class="example-break">
769
770 </div>
771
772 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="MatchTracker"></a>3.6. <code class="literal">MatchTracker</code></h3></div></div></div>
773
774
775 <p>Sometimes you might be interested in any sort of
776 comparison result and want to get notified of successful matches
777 as well. Maybe you want to provide feedback on the amount of
778 differences and similarities between two documents, for
779 example.</p>
780
781 <p>The interface <code class="literal">MatchTracker</code> can be
782 implemented to get notified on each and every successful match,
783 note that there may be a lot more comparisons going on than you
784 might expect and that your callback gets notified a lot.</p>
785
786 <div class="example"><a name="idp43070192"></a><p class="title"><b>Example 23. The <code class="literal">MatchTracker</code> interface</b></p><div class="example-contents">
787
788 <pre class="programlisting">
789 package org.custommonkey.xmlunit;
790
791 /**
792 * Listener for callbacks from a {@link DifferenceEngine#compare
793 * DifferenceEngine comparison} that is notified on each and every
794 * comparision that resulted in a match.
795 */
796 public interface MatchTracker {
797 /**
798 * Receive notification that 2 match.
799 * @param match a Difference instance as defined in {@link
800 * DifferenceConstants DifferenceConstants} describing the test
801 * that matched and containing the detail of the nodes that have
802 * been compared
803 */
804 void matchFound(Difference difference);
805 }
806 </pre></div></div><br class="example-break">
807
808 <p>Despite its name the <code class="literal">Difference</code>
809 instance passed into the <code class="literal">matchFound</code> method
810 really describes a match and not a difference. You can expect
811 that the <code class="literal">getValue</code> method on both the
812 control and the test <code class="literal">NodeDetail</code> will be
813 equal.</p>
814
815 <p><code class="literal">DifferenceEngine</code> provides a constructor
816 overload that allows you to pass in
817 a <code class="literal">MatchTracker</code> instance and also provides
818 a <code class="literal">setMatchTracker</code>
819 method. <code class="literal">Diff</code>
820 and <code class="literal">DetailedDiff</code>
821 provide <code class="literal">overrideMatchTracker</code> methods that
822 fill the same purpose.</p>
823
824 <p>Note that your <code class="literal">MatchTracker</code> won't
825 receive any callbacks once the
826 configured <code class="literal">ComparisonController</code> has decided
827 that <code class="literal">DifferenceEngine</code> should halt the
828 comparison.</p>
829
830 </div>
831
832 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Comparing:%20JUnit%203"></a>3.7. JUnit 3.x Convenience Methods</h3></div></div></div>
833
834
835 <p><code class="literal">XMLAssert</code> and
836 <code class="literal">XMLTestCase</code> contain quite a few overloads of
837 methods for comparing two pieces of XML.</p>
838
839 <p>The method's names use the word <code class="literal">Equal</code>
840 to mean the same as <code class="literal">similar</code> in the
841 <code class="literal">Diff</code> class (or throughout this guide). So
842 <code class="literal">assertXMLEqual</code> will assert that only
843 recoverable differences have been encountered where
844 <code class="literal">assertXMLNotEqual</code> asserts that some
845 differences have been non-recoverable.
846 <code class="literal">assertXMLIdentical</code> asserts that there haven't
847 been any differences at all while
848 <code class="literal">assertXMLNotIdentical</code> asserts that there have
849 been differences (recoverable or not).</p>
850
851 <p>Most of the overloads of <code class="literal">assertXMLEqual</code>
852 just provide different means to specify the pieces of XML as
853 <code class="literal">String</code>s, <code class="literal">InputSource</code>s,
854 <code class="literal">Reader</code>s<a href="#ftn.idp43096928" class="footnote" name="idp43096928"><sup class="footnote">[7]</sup></a> or <code class="literal">Document</code>s. For each
855 method there is a version that takes an additional
856 <code class="literal">err</code> argument which is used to create the
857 message if the assertion fails.</p>
858
859 <p>If you don't need any control over the
860 <code class="literal">ElementQualifier</code> or
861 <code class="literal">DifferenceListener</code> used by
862 <code class="literal">Diff</code> these methods will save some boilerplate
863 code. If <code class="literal">CONTROL</code> and <code class="literal">TEST</code>
864 are pieces of XML represented as one of the supported inputs
865 then</p>
866
867 <pre class="programlisting">
868 Diff d = new Diff(CONTROL, TEST);
869 assertTrue("expected pieces to be similar, " + d.toString(),
870 d.similar());
871 </pre>
872
873 <p>and</p>
874
875 <pre class="programlisting">
876 assertXMLEqual("expected pieces to be similar", CONTROL, TEST);
877 </pre>
878
879 <p>are equivalent.</p>
880
881 <p>If you need more control over the <code class="literal">Diff</code>
882 instance there is a version of <code class="literal">assertXMLEqual</code>
883 (and <code class="literal">assertXMLIdentical</code>) that accepts a
884 <code class="literal">Diff</code> instance as its argument as well as a
885 <code class="literal">boolean</code> indicating whether you expect the
886 <code class="literal">Diff</code> to be <code class="literal">similar</code>
887 (<code class="literal">identical</code>) or not.</p>
888
889 <p><code class="literal">XMLTestCase</code> contains a couple of
890 <code class="literal">compareXML</code> methods that really are only
891 shortcuts to <code class="literal">Diff</code>'s constructors.</p>
892
893 <p>There is no way to use <code class="literal">DifferenceEngine</code>
894 or <code class="literal">DetailedDiff</code> directly via the convenience
895 methods.</p>
896
897 </div>
898
899 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Comparing:%20Configuration"></a>3.8. Configuration Options</h3></div></div></div>
900
901
902 <p>Unless you are using <code class="literal">Document</code> or
903 <code class="literal">DOMSource</code> overrides when specifying your
904 pieces of XML, XMLUnit will use the configured XML parsers (see
905 <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>) and <code class="literal">EntityResolver</code>s
906 (see <a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2. EntityResolver">Section 2.4.2, &#8220;<code class="literal">EntityResolver</code>&#8221;</a>). There are configuration
907 options to use different settings for the control and test
908 pieces of XML.</p>
909
910 <p>In addition some of the other configuration settings may
911 lead to XMLUnit using the configured XSLT transformer (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>) under the covers.</p>
912
913 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Whitespace%20Handling"></a>3.8.1. Whitespace Handling</h4></div></div></div>
914
915
916 <p>Two different configuration options affect how XMLUnit
917 treats whitespace in comparisons:</p>
918
919 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Element Content Whitespace (see <a class="xref" href="ar01s02.html#Basic:%20Element%20Content%20Whitespace" title="2.4.3. Element Content Whitespace">Section 2.4.3, &#8220;Element Content Whitespace&#8221;</a>)
920
921 <p>If XMLUnit has been configured to ignore element
922 content whitespace it will trim any text nodes found by
923 the parser. This means that there won't appear to be any
924 textual content in element <code class="literal">&lt;foo&gt;</code>
925 for the following example. If you don't set
926 <code class="literal">XMLUnit.setIgnoreWhitespace</code> there would
927 be textual content consisting of a new line
928 character.</p>
929
930 <pre class="programlisting">
931 &lt;foo&gt;
932 &lt;/foo&gt;
933 </pre>
934
935 <p>At the same time the following two
936 <code class="literal">&lt;foo&gt;</code> elements will be considered
937 identical if the option has been enabled, though.</p>
938
939 <pre class="programlisting">
940 &lt;foo&gt;bar&lt;/foo&gt;
941 &lt;foo&gt; bar &lt;/foo&gt;
942 </pre>
943
944 <p>When this option is set to <code class="literal">true</code>,
945 <code class="literal">Diff</code> will use the XSLT transformer
946 under the covers.</p>
947 </li><li class="listitem">"Normalizing" Whitespace
948
949 <p>If you set
950 <code class="literal">XMLUnit.setNormalizeWhitespace</code> to true
951 then XMLUnit will replace any kind of whitespace found in
952 character content with a SPACE character and collapse
953 consecutive whitespace characters to a single SPACE. It
954 will also trim the resulting character content on both
955 ends.</p>
956
957 <p>The following two <code class="literal">&lt;foo&gt;</code>
958 elements will be considered identical if the option has
959 been set:</p>
960
961 <pre class="programlisting">
962 &lt;foo&gt;bar baz&lt;/foo&gt;
963 &lt;foo&gt; bar
964 baz&lt;/foo&gt;
965 </pre>
966
967 <p>Note that this is not related to "normalizing" the
968 document as a whole (see <a class="xref" href="ar01s03.html#Normalizing%20Documents" title='3.8.2. "Normalizing" Documents'>Section 3.8.2, &#8220;"Normalizing" <code class="literal">Document</code>s&#8221;</a>).</p>
969
970 </li></ul></div>
971 </div>
972
973 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Normalizing%20Documents"></a>3.8.2. "Normalizing" <code class="literal">Document</code>s</h4></div></div></div>
974
975
976 <p>"Normalize" in this context corresponds to the
977 <code class="literal">normalize</code> method in DOM's
978 <code class="literal">Document</code> class. It is the process of
979 merging adjacent <code class="literal">Text</code> nodes and is not
980 related to "normalizing whitespace" as described in the
981 previous section.</p>
982
983 <p>Usually you don't need to care about this option since
984 the XML parser is required to normalize the
985 <code class="literal">Document</code> when creating it. The only reason
986 you may want to change the option via
987 <code class="literal">XMLUnit.setNormalize</code> is that your
988 <code class="literal">Document</code> instances have not been created by
989 an XML parser but rather been put together in memory using the
990 DOM API directly.</p>
991 </div>
992
993 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Ignoring%20Comments"></a>3.8.3. Ignoring Comments</h4></div></div></div>
994
995
996 <p>Using <code class="literal">XMLUnit.setIgnoreComments</code> you
997 can make XMLUnit's difference engine ignore comments
998 completely.</p>
999
1000 <p>When this option is set to <code class="literal">true</code>,
1001 <code class="literal">Diff</code> will use the XSLT transformer under
1002 the covers.</p>
1003 </div>
1004
1005 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Treating%20CDATA%20Sections%20and%20Text%20Nodes%20Alike"></a>3.8.4. Treating CDATA Sections and Text Nodes Alike</h4></div></div></div>
1006
1007
1008 <p>It is not always necessary to know whether a text has
1009 been put into a CDATA section or not. Using
1010 <code class="literal">XMLUnit.setIgnoreDiffBetweenTextAndCDATA</code>
1011 you can make XMLUnit consider the following two pieces of XML
1012 identical:</p>
1013
1014 <pre class="programlisting">
1015 &lt;foo&gt;&amp;lt;bar&amp;gt;&lt;/foo&gt;
1016 </pre>
1017 <pre class="programlisting">
1018 &lt;foo&gt;&lt;![CDATA[&lt;bar&gt;]]&gt;&lt;/foo&gt;
1019 </pre>
1020 </div>
1021
1022 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Entity%20Reference%20Expansion"></a>3.8.5. Entity Reference Expansion</h4></div></div></div>
1023
1024
1025 <p>Normally the XML parser will expand character references
1026 to their Unicode equivalents but for more complex entity
1027 definitions the parser may expand them or not.
1028 Using <code class="literal">XMLUnit.setExpandEntityReferences</code> you
1029 can control the parser's setting.</p>
1030
1031 </div>
1032
1033 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Comparison%20of%20Unmatched%20Elements"></a>3.8.6. Comparison of Unmatched Elements</h4></div></div></div>
1034
1035
1036 <p>When XMLUnit cannot match a control Element to a test
1037 Element (the configured ElementQualifier - see
1038 <a class="xref" href="ar01s03.html#ElementQualifier" title="3.4. ElementQualifier">Section 3.4, &#8220;<code class="literal">ElementQualifier</code>&#8221;</a> - doesn't return true for
1039 any of the test Elements) it will try to compare it against
1040 the first unmatched test Element (if there is one).
1041 Starting with XMLUnit 1.3 one can
1042 use <code class="literal">XMLUnit.setCompareUnmatched</code> to
1043 disable this behavior and
1044 generate <code class="literal">CHILD_NODE_NOT_FOUND</code> differences
1045 instead.</p>
1046
1047 <p>If the control document is
1048 </p><pre class="programlisting">
1049 &lt;root&gt;
1050 &lt;a/&gt;
1051 &lt;/root&gt;
1052 </pre><p>
1053 and the test document is
1054 </p><pre class="programlisting">
1055 &lt;root&gt;
1056 &lt;b/&gt;
1057 &lt;/root&gt;
1058 </pre><p>
1059
1060 the default setting will create a
1061 single <code class="literal">ELEMENT_TAG_NAME</code> Difference
1062 ("expected a but found b").
1063 Setting <code class="literal">XMLUnit.setCompareUnmatched</code> to
1064 false will create two Differences of
1065 type <code class="literal">CHILD_NODE_NOT_FOUND</code> (one for "a" and
1066 one for "b") instead.</p>
1067 </div>
1068
1069 </div>
1070 <div class="footnotes"><br><hr style="width:100; text-align:left;margin-left: 0"><div id="ftn.idp43096928" class="footnote"><p><a href="#idp43096928" class="para"><sup class="para">[7] </sup></a>See <a class="xref" href="ar01s02.html#Providing%20Input%20to%20XMLUnit" title="2.5. Providing Input to XMLUnit">Section 2.5, &#8220;Providing Input to XMLUnit&#8221;</a> for some advice on choosing your input
1071 format.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2. Using XMLUnit </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4. Validating XML Documents</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>4. Validating XML Documents</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s03.html" title="3. Comparing Pieces of XML"><link rel="next" href="ar01s05.html" title="5. XPath Tests"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. Validating XML Documents</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Validating%20XML%20Documents"></a>4. Validating XML Documents</h2></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="The%20Validator%20Class"></a>4.1. The <code class="literal">Validator</code> Class</h3></div></div></div>
4
5
6 <p>The <code class="literal">Validator</code> class encapsulates
7 XMLUnit's validation support. It will use the
8 <code class="literal">SAXParser</code> configured in XMLUnit (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>).</p>
9
10 <p>The piece of XML to validate is specified in the
11 constructor. The constructors using more than a single argument
12 are only relevant if you want to validate against a DTD and need
13 to provide the location of the DTD itself - for details see the
14 next section.</p>
15
16 <p>By default, <code class="literal">Validator</code> will validate
17 against a DTD, but it is possible to validate against a (or
18 multiple) Schema(s) as well. Schema validation requires an XML
19 parser that supports it, of course.</p>
20
21 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="DTD%20Validation"></a>4.1.1. DTD Validation</h4></div></div></div>
22
23 </div>
24
25 <p>Validating against a DTD is straight forward if the piece
26 of XML contains a <code class="literal">DOCTYPE</code> declaration with a
27 <code class="literal">SYSTEM</code> identifier that can be resolved at
28 validation time. Simply create a <code class="literal">Validator</code>
29 object using one of the single argument constructors.</p>
30
31 <div class="example"><a name="idp43179280"></a><p class="title"><b>Example 24. Validating Against the DTD Defined in
32 <code class="literal">DOCTYPE</code></b></p><div class="example-contents">
33
34 <pre class="programlisting">
35 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
36 Validator v = new Validator(is);
37 boolean isValid = v.isValid();
38 </pre></div></div><br class="example-break">
39
40 <p>If the piece of XML doesn't contain any
41 <code class="literal">DOCTYPE</code> declaration at all or it contains a
42 <code class="literal">DOCTYPE</code> but you want to validate against a
43 different DTD, you'd use one of the three argument versions of
44 <code class="literal">Validator</code>'s constructors. In this case the
45 <code class="literal">publicId</code> argument becomes the
46 <code class="literal">PUBLIC</code> and <code class="literal">systemId</code> the
47 <code class="literal">SYSTEM</code> identifier of the
48 <code class="literal">DOCTYPE</code> that is implicitly added to the piece
49 of XML. Any existing <code class="literal">DOCTYPE</code> will be
50 removed. The <code class="literal">systemId</code> should be a URL that
51 can be resolved by your parser.</p>
52
53 <div class="example"><a name="idp43189808"></a><p class="title"><b>Example 25. Validating a Piece of XML that doesn't Contain a
54 <code class="literal">DOCTYPE</code></b></p><div class="example-contents">
55
56 <pre class="programlisting">
57 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
58 Validator v = new Validator(is,
59 (new File(myDTD)).toURI().toURL().toString(),
60 myPublicId);
61 boolean isValid = v.isValid();
62 </pre></div></div><br class="example-break">
63
64 <p>If the piece of XML already has the correct
65 <code class="literal">DOCTYPE</code> declaration but the declaration
66 either doesn't specify a <code class="literal">SYSTEM</code> identifier at
67 all or you want the <code class="literal">SYSTEM</code> identifier to
68 resolve to a different location you have two options:</p>
69
70 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Use one of the two argument constructors and specify
71 the alternative URL as
72 <code class="literal">systemId</code>.
73
74 <div class="example"><a name="idp43196880"></a><p class="title"><b>Example 26. Validating Against a Local DTD</b></p><div class="example-contents">
75
76 <pre class="programlisting">
77 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
78 Validator v = new Validator(is,
79 (new File(myDTD)).toURI().toURL().toString());
80 boolean isValid = v.isValid();
81 </pre></div></div><br class="example-break">
82 </li><li class="listitem">Use a custom <code class="literal">EntityResolver</code> via
83 <code class="literal">XMLUnit.setControlEntityResolver</code> together
84 with one of the single argument constructor overloads of
85 Validator.
86
87 <p>This approach would allow you to use an OASIS
88 catalog<a href="#ftn.idp43201200" class="footnote" name="idp43201200"><sup class="footnote">[8]</sup></a>
89 in conjunction with the Apache XML Resolver
90 library<a href="#ftn.idp43202544" class="footnote" name="idp43202544"><sup class="footnote">[9]</sup></a>
91 to resolve the DTD location as well as the location of any
92 other entity in your piece of XML, for example.</p>
93
94 <div class="example"><a name="idp43203888"></a><p class="title"><b>Example 27. Validating Against a DTD Using Apache's XML Resolver and
95 an XML Catalog</b></p><div class="example-contents">
96
97 <pre class="programlisting">
98 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
99 XMLUnit.setControlEntityResolver(new CatalogResolver());
100 Validator v = new Validator(is);
101 boolean isValid = v.isValid();
102 </pre>
103
104 <pre class="programlisting">
105 #CatalogManager.properties
106
107 verbosity=1
108 relative-catalogs=yes
109 catalogs=/some/path/to/catalog
110 prefer=public
111 static-catalog=yes
112 catalog-class-name=org.apache.xml.resolver.Resolver
113 </pre>
114
115 <pre class="programlisting">
116 &lt;!-- catalog file --&gt;
117
118 &lt;catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"&gt;
119 &lt;public publicId="-//Some//DTD V 1.1//EN"
120 uri="mydtd.dtd"/&gt;
121 &lt;/catalog&gt;
122 </pre>
123
124 </div></div><br class="example-break">
125
126 </li></ul></div>
127
128 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="XML%20Schema%20Validation"></a>4.1.2. XML Schema Validation</h4></div></div></div>
129
130 </div>
131
132 <p>In order to validate against the XML Schema language
133 Schema validation has to be enabled via the
134 <code class="literal">useXMLSchema</code> method of
135 <code class="literal">Validator</code>.</p>
136
137 <p>By default the parser will try to resolve the location of
138 Schema definition files via a <code class="literal">schemaLocation</code>
139 attribute if it is present in the piece of XML or it will try to
140 open the Schema's URI as an URL and read from it.</p>
141
142 <p>The <code class="literal">setJAXP12SchemaSource</code> method of
143 <code class="literal">Validator</code> allows you to override this
144 behavior as long as the parser supports the
145 <code class="literal">http://java.sun.com/xml/jaxp/properties/schemaSource</code>
146 property in the way described in "JAXP 1.2 Approved
147 CHANGES"<a href="#ftn.idp43215232" class="footnote" name="idp43215232"><sup class="footnote">[10]</sup></a>.</p>
148
149 <p><code class="literal">setJAXP12SchemaSource</code>'s argument can be
150 one of</p>
151
152 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">A <code class="literal">String</code> which contains an
153 URI.</li><li class="listitem">An <code class="literal">InputStream</code> the Schema can be
154 read from.</li><li class="listitem">An <code class="literal">InputSource</code> the Schema can be
155 read from.</li><li class="listitem">A <code class="literal">File</code> the Schema can be
156 read from.</li><li class="listitem">An array containing any of the above.</li></ul></div>
157
158 <p>If the property has been set using a
159 <code class="literal">String</code>, the <code class="literal">Validator</code>
160 class will provide its <code class="literal">systemId</code> as specified
161 in the constructor when asked to resolve it. You must only use
162 the single argument constructors if you want to avoid this
163 behavior. If no <code class="literal">systemId</code> has been specified,
164 the configured <code class="literal">EntityResolver</code> may still be
165 used.</p>
166
167 <div class="example"><a name="schema-jaxp12"></a><p class="title"><b>Example 28. Validating Against a Local XML Schema</b></p><div class="example-contents">
168
169 <pre class="programlisting">
170 InputSource is = new InputSource(new FileInputStream(myXmlDocument));
171 Validator v = new Validator(is);
172 v.useXMLSchema(true);
173 v.setJAXP12SchemaSource(new File(myXmlSchemaFile));
174 boolean isValid = v.isValid();
175 </pre></div></div><br class="example-break">
176
177 </div>
178
179 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Validation:%20JUnit%203"></a>4.2. JUnit 3.x Convenience Methods</h3></div></div></div>
180
181
182 <p>Both <code class="literal">XMLAssert</code> and
183 <code class="literal">XMLTestCase</code> provide an
184 <code class="literal">assertXMLValid(Validator)</code> method that will
185 fail if <code class="literal">Validator</code>'s
186 <code class="literal">isValid</code> method returns
187 <code class="literal">false</code>.</p>
188
189 <p>In addition several overloads of the
190 <code class="literal">assertXMLValid</code> method are provided that
191 directly correspond to similar overloads of
192 <code class="literal">Validator</code>'s constructor. These overloads
193 don't support XML Schema validation at all.</p>
194
195 <p><code class="literal">Validator</code> itself provides an
196 <code class="literal">assertIsValid</code> method that will throw an
197 <code class="literal">AssertionFailedError</code> if validation
198 fails.</p>
199
200 <p>Neither method provides any control over the message of
201 the <code class="literal">AssertionFailedError</code> in case of a
202 failure.</p>
203 </div>
204
205 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Validation:%20Configuration"></a>4.3. Configuration Options</h3></div></div></div>
206
207
208 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">Validator</code> uses a SAX parser
209 created by the configured SAX parser factory (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>).</li><li class="listitem">It will use the "control"
210 <code class="literal">EntityResolver</code> if one has been specified
211 (see <a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2. EntityResolver">Section 2.4.2, &#8220;<code class="literal">EntityResolver</code>&#8221;</a>).</li><li class="listitem">The location of a DTD can be specified via
212 <code class="literal">Validator</code>'s <code class="literal">systemId</code>
213 constructor argument or a custom EntityResolver (see <a class="xref" href="ar01s04.html#DTD%20Validation" title="4.1.1. DTD Validation">Section 4.1.1, &#8220;DTD Validation&#8221;</a>).</li><li class="listitem">XML Schema validation is enabled via
214 <code class="literal">Validator.useXMLSchema(true)</code>.</li><li class="listitem">The location(s) of XML Schema document(s) can be
215 specified via
216 <code class="literal">Validator.setJAXP12SchemaSource</code> (see <a class="xref" href="ar01s04.html#XML%20Schema%20Validation" title="4.1.2. XML Schema Validation">Section 4.1.2, &#8220;XML Schema Validation&#8221;</a>).</li></ul></div>
217 </div>
218
219 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="JAXP%201.3%20Validation"></a>4.4. JAXP 1.3 Validation</h3></div></div></div>
220
221
222 <p>JAXP 1.3 - shipping with Java5 or better and available as
223 a separate product for earlier Java VMs - introduces a new
224 package <a class="ulink" href="https://jaxp-sources.dev.java.net/nonav/docs/api/" target="_top"><code class="literal">javax.xml.validation</code></a>
225 designed for validations of snippets of XML against different
226 schema languages. Any compliant implementation must support the
227 W3C XML Schema language, but other languages
228 like <a class="ulink" href="http://www.relaxng.org/" target="_top">RELAX NG</a> or
229 <a class="ulink" href="http://www.schematron.com/" target="_top">Schematron</a> may
230 be supported as well.</p>
231
232 <p>The
233 class <code class="literal">org.custommonkey.xmlunit.jaxp13.Validator</code>
234 can be used to validate a piece of XML against a schema
235 definition but also to validate the schema definition itself.
236 By default <code class="literal">Validator</code> will assume your
237 definition uses the W3C XML Schema language, but it provides a
238 constructor that can be used to specify a different language via
239 an URL supported by the <code class="literal">SchemaFactory</code> class.
240 Alternatively you can specify the schema factory itself.</p>
241
242 <p>The schema definition itself can be given via
243 <code class="literal">Source</code> elements, just like the pieces of XML
244 to validate are specified as <code class="literal">Source</code> as
245 well.</p>
246
247 <p>Note the <code class="literal">Validator</code> class
248 of <code class="literal">javax.xml.validation</code> will ignore all
249 <code class="literal">xsi:namespaceLocation</code> and
250 <code class="literal">xsi:noNamespaceLocation</code> attributes of the XML
251 document you want to validate if you specify at least one schema
252 source.</p>
253
254 <p>The following example
255 uses <code class="literal">org.custommonkey.xmlunit.jaxp13.Validator</code>
256 to perform the same type of validation shown in
257 <a class="xref" href="ar01s04.html#schema-jaxp12" title="Example 28. Validating Against a Local XML Schema">Example 28, &#8220;Validating Against a Local XML Schema&#8221;</a>.</p>
258
259 <div class="example"><a name="schema-jaxp13"></a><p class="title"><b>Example 29. Validating Against a Local XML Schema</b></p><div class="example-contents">
260
261 <pre class="programlisting">
262 Validator v = new Validator();
263 v.addSchemaSource(new StreamSource(new File(myXmlSchemaFile)));
264 StreamSource is = new StreamSource(new File(myXmlDocument));
265 boolean isValid = v.isInstanceValid(is);
266 </pre></div></div><br class="example-break">
267
268 <p>Validating a schema definition is shown in the next
269 example.</p>
270
271 <div class="example"><a name="idp43269232"></a><p class="title"><b>Example 30. Validating an XML Schema Definition</b></p><div class="example-contents">
272
273 <pre class="programlisting">
274 Validator v = new Validator();
275 v.addSchemaSource(new StreamSource(new File(myXmlSchemaFile)));
276 boolean isValid = v.isSchemaValid();
277 </pre></div></div><br class="example-break">
278
279 <p>There is no explicit JUnit 3 support
280 for <code class="literal">org.custommonkey.xmlunit.jaxp13.Validator</code>.</p>
281
282 </div>
283
284 <div class="footnotes"><br><hr style="width:100; text-align:left;margin-left: 0"><div id="ftn.idp43201200" class="footnote"><p><a href="#idp43201200" class="para"><sup class="para">[8] </sup></a><a class="ulink" href="http://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html" target="_top">http://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html</a></p></div><div id="ftn.idp43202544" class="footnote"><p><a href="#idp43202544" class="para"><sup class="para">[9] </sup></a><a class="ulink" href="http://xml.apache.org/commons/components/resolver/index.html" target="_top">http://xml.apache.org/commons/components/resolver/index.html</a></p></div><div id="ftn.idp43215232" class="footnote"><p><a href="#idp43215232" class="para"><sup class="para">[10] </sup></a><a class="ulink" href="http://java.sun.com/webservices/jaxp/change-requests-11.html" target="_top">http://java.sun.com/webservices/jaxp/change-requests-11.html</a></p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3. Comparing Pieces of XML </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 5. XPath Tests</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>5. XPath Tests</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s04.html" title="4. Validating XML Documents"><link rel="next" href="ar01s06.html" title="6. DOM Tree Walking"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5. XPath Tests</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="XPath%20Tests"></a>5. XPath Tests</h2></div></div></div>
1
2
3 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="XPath%20Engines"></a>5.1. XPath Engines</h3></div></div></div>
4
5
6 <p>Central to XMLUnit's XPath support is the
7 <code class="literal">XpathEngine</code> interface which consists of only
8 three methods:</p>
9
10 <pre class="programlisting">
11 /**
12 * Execute the specified xpath syntax &lt;code&gt;select&lt;/code&gt; expression
13 * on the specified document and return the list of nodes (could have
14 * length zero) that match
15 * @param select
16 * @param document
17 * @return list of matching nodes
18 */
19 NodeList getMatchingNodes(String select, Document document)
20 throws XpathException;
21
22 /**
23 * Evaluate the result of executing the specified XPath syntax
24 * &lt;code&gt;select&lt;/code&gt; expression on the specified document
25 * @param select
26 * @param document
27 * @return evaluated result
28 */
29 String evaluate(String select, Document document)
30 throws XpathException;
31
32 /**
33 * Establish a namespace context.
34 */
35 void setNamespaceContext(NamespaceContext ctx);
36 </pre>
37
38
39 <p>The first two methods expect an XPath expression that
40 selects content from the DOM document that is the second
41 argument. The result of the selection can be either a DOM
42 <code class="literal">NodeList</code> or a <code class="literal">String</code>. The
43 later form tries to flatten the result, the value is said to be
44 "String-ified".</p>
45
46 <p>The third method is part of XMLUnit's support for XML
47 Namespaces in XPath expressions. See <a class="xref" href="ar01s05.html#Using%20XML%20Namespaces%20in%20XPath%20Selectors" title="5.2. Using XML Namespaces in XPath Selectors">Section 5.2, &#8220;Using XML Namespaces in XPath Selectors&#8221;</a>
48 for more details.</p>
49
50 <p>There are two implementations of the interface,
51 <code class="literal">org.custommonkey.xmlunit.SimpleXpathEngine</code>
52 and
53 <code class="literal">org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine</code>.
54 The first implementation is the only one available in XMLUnit
55 1.0 and uses the configured JAXP XSLT
56 transformer. The second is new to XMLUnit 1.1 and only
57 available if JAXP 1.3 or later is supported, which should be the
58 case for Java 5 and later.</p>
59
60 <p><code class="literal">XpathException</code> is an
61 <code class="literal">Exception</code> that will be thrown for invalid
62 XPath expressions or other problems with the underlying XPath
63 engine. It will typically wrap a
64 <code class="literal">javax.xml.xpath.XPathExpressionException</code> in
65 the <code class="literal">Jaxp13XpathEngine</code> case or a
66 <code class="literal">javax.xml.transform.TransformerException</code> when
67 <code class="literal">SimpleXpathEngine</code> is used.</p>
68
69 <p>The <code class="literal">XMLUnit.newXpathEngine</code> method will
70 first try to create an instance of
71 <code class="literal">Jaxp13XpathEngine</code> and fall back to
72 <code class="literal">SimpleXpathEngine</code> if JAXP 1.3 is not
73 supported.</p>
74
75 <p>One example of using the XPath support is included inside
76 it <code class="literal">org.custommonkey.xmlunit.examples</code> package.
77 It asserts that the string-ified form of an XPath selection
78 matches a regular expression. The code needed for this
79 is:</p>
80
81 <div class="example"><a name="idp43292848"></a><p class="title"><b>Example 31. Matching an XPath Selection Against a Regular
82 Expression</b></p><div class="example-contents">
83
84 <pre class="programlisting">
85 XpathEngine engine = XMLUnit.newXpathEngine();
86 String value = engine.evaluate(xpath, doc);
87 Assert.assertTrue(message, value.matches(regex));
88 </pre></div></div><br class="example-break">
89
90 </div>
91
92 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Using%20XML%20Namespaces%20in%20XPath%20Selectors"></a>5.2. Using XML Namespaces in XPath Selectors</h3></div></div></div>
93
94
95 <p>Starting with XMLUnit 1.1 XML Namespaces are supported for
96 XPath queries.</p>
97
98 <p>The <code class="literal">NamespaceContext</code> interface provides
99 a mapping from prefix to namespace URI and is used by the XPath
100 engine. XPath selections then use the mapping's prefixes where
101 needed. Note that a prefix used in the document under test and
102 a prefix given as part of the
103 <code class="literal">NamespaceContext</code> are not related at all; the
104 context only applies to the XPath expression, the prefix used in
105 the document is ignored completely.</p>
106
107 <p>Right now XMLUnit provides only a single implementation of
108 the <code class="literal">NamespaceContext</code> interface:
109 <code class="literal">SimpleNamespaceContext</code>. This implementation
110 expects a <code class="literal">java.util.Map</code> as its constructor
111 argument. The <code class="literal">Map</code> must contain
112 (<code class="literal">String</code>) prefixes as keys and
113 (<code class="literal">String</code>) namespace URIs as values.</p>
114
115 <p>Note there is nothing like a default namespace in XPath
116 selectors. If you are using namespaces in your XPath, all
117 namespaces need a prefix (of length greater than zero). This
118 is independent of the prefixes used in your document.</p>
119
120 <p>The following example is taken from XMLUnit's own tests.
121 It demonstrates that the namespace prefix of the document under
122 test is irrelevant and shows how to set up the namespace
123 context.</p>
124
125 <div class="example"><a name="idp43304720"></a><p class="title"><b>Example 32. Using Namespaces in XPath Tests</b></p><div class="example-contents">
126
127 <pre class="programlisting">
128 String testDoc = "&lt;t:test xmlns:t=\"urn:foo\"&gt;&lt;t:bar/&gt;&lt;/t:test&gt;";
129 Document d = XMLUnit.buildControlDocument(testDoc);
130 HashMap m = new HashMap();
131 m.put("foo", "urn:foo");
132
133 NamespaceContext ctx = new SimpleNamespaceContext(m);
134 XpathEngine engine = XMLUnit.newXpathEngine();
135 engine.setNamespaceContext(ctx);
136
137 NodeList l = engine.getMatchingNodes("//foo:bar", d);
138 assertEquals(1, l.getLength());
139 assertEquals(Node.ELEMENT_NODE, l.item(0).getNodeType());
140 </pre></div></div><br class="example-break">
141
142 <p>In some cases the "stringified" value of an XPath
143 evaluation is a qualified name - a string that encodes a
144 namespace URI together with a local name. There are two common
145 formats for such qualified names, one used by Java5's
146 <code class="literal">QName</code> in the format
147 <code class="literal">{NS-URI}LOCAL-NAME</code> and one using
148 <code class="literal">PREFIX:LOCAL-NAME</code>. Starting with XMLUnit 1.6
149 a new <code class="literal">QualifiedName</code> class can parse either
150 representation. The <code class="literal">assertXpathEvaluatesTo</code>
151 overloads where the expected value is a
152 <code class="literal">QualifiedName</code> try to parse the stringified
153 value in either format - using the documents namespace context
154 when parsing the actual value.</p>
155
156 <p>It is possible to set a global
157 <code class="literal">NamespaceContext</code>, see <a class="xref" href="ar01s05.html#XPath:%20Configuration" title="5.4. Configuration Options">Section 5.4, &#8220;Configuration Options&#8221;</a> for details.</p>
158 </div>
159
160 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="XPath:%20JUnit%203"></a>5.3. JUnit 3.x Convenience Methods</h3></div></div></div>
161
162
163 <p><code class="literal">XMLTestCase</code> and
164 <code class="literal">XMLAssert</code> provide several overloads for the
165 following common types of assertions:</p>
166
167 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Two XPath expression should return the same DOM
168 <code class="literal">NodeList</code> as result:
169 <code class="literal">assertXpathsEqual</code>. There are methods that
170 use two different expressions on the same document and others
171 that compare expressions selecting from two different
172 documents.
173
174 <p>The <code class="literal">NodeList</code>s are wrapped into a
175 surrogate root XML element and the resulting DOM
176 <code class="literal">Document</code>s are compared using
177 <code class="literal">Diff.similar()</code>.</p>
178 </li><li class="listitem">The opposite of the above, the expressions should
179 yield different results:
180 <code class="literal">assertXpathsNotEqual</code>.</li><li class="listitem">Two XPath expression should return the same
181 "String-ified" result:
182 <code class="literal">assertXpathValuesEqual</code>. There are methods
183 that use two different expressions on the same document and
184 others that compare expressions selecting from two different
185 documents.</li><li class="listitem">The opposite of the above, the expressions should
186 yield different results:
187 <code class="literal">assertXpathValuesNotEqual</code>.</li><li class="listitem">The XPath expression should return an expected value
188 when "String-ified" or interpreted as qualified name:
189 <code class="literal">assertXpathEvaluatesTo</code>.</li><li class="listitem">The <code class="literal">NodeList</code> selected by an XPath
190 expression is not empty:
191 <code class="literal">assertXpathExists</code>.</li><li class="listitem">The <code class="literal">NodeList</code> selected by an XPath
192 expression is empty:
193 <code class="literal">assertXpathNotExists</code>.</li></ul></div>
194
195 <p>Neither method provides any control over the message of
196 the <code class="literal">AssertionFailedError</code> in case of a
197 failure.</p>
198 </div>
199
200 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="XPath:%20Configuration"></a>5.4. Configuration Options</h3></div></div></div>
201
202
203 <p>When using <code class="literal">XpathEngine</code> directly you are
204 responsible for creating the DOM document yourself. If you use
205 the convenience methods of <code class="literal">XMLTestCase</code> or
206 <code class="literal">XMLAssert</code> you have several options to specify
207 the input; XMLUnit will use the control or test parser that has
208 been configured (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>) to create a DOM
209 document from the given piece of XML in that case - using the
210 configured <code class="literal">EntityResolver</code>(s) (see <a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2. EntityResolver">Section 2.4.2, &#8220;<code class="literal">EntityResolver</code>&#8221;</a>) if any.</p>
211
212 <p>If JAXP 1.3 is not available,
213 <code class="literal">SimpleXpathEngine</code> will use the configured
214 JAXP XSLT transformer (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>) under the
215 covers.</p>
216
217 <p>When using JAXP 1.3 you can chose the actual
218 <code class="literal">XPathFactory</code> implementation using
219 <code class="literal">XMLUnit.setXPathFactory</code>.</p>
220
221 <p>It is possible to establish a global
222 <code class="literal">NamespaceContext</code> with the help of the
223 <code class="literal">XMLUnit.setXpathNamespaceContext</code> method. Any
224 <code class="literal">XpathEngine</code> created by
225 <code class="literal">XMLUnit.newXpathEngine</code> will automatically use
226 the given context. Note that the JUnit 3 convenience methods
227 use <code class="literal">XMLUnit.newXpathEngine</code> implicitly and
228 will thus use the configured
229 <code class="literal">NamespaceContext</code>.</p>
230
231 </div>
232 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4. Validating XML Documents </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6. DOM Tree Walking</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>6. DOM Tree Walking</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s05.html" title="5. XPath Tests"><link rel="next" href="apa.html" title="A. Changes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. DOM Tree Walking</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="apa.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="DOM%20Tree%20Walking"></a>6. DOM Tree Walking</h2></div></div></div>
1
2
3 <p>Sometimes it is easier to test a piece of XML's validity by
4 traversing the whole document node by node and test each node
5 individually. Maybe there is no control XML to validate against
6 or the expected value of an element's content has to be
7 calculated. There may be several reasons.</p>
8
9 <p>XMLUnit supports this approach of testing via the
10 <code class="literal">NodeTest</code> class. In order to use it, you need a
11 DOM implementation that generates <code class="literal">Document</code>
12 instances that implement the optional
13 <code class="literal">org.w3c.traversal.DocumentTraversal</code> interface,
14 which is not part of JAXP's standardized DOM support.</p>
15
16 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DocumentTraversal"></a>6.1. <code class="literal">DocumentTraversal</code></h3></div></div></div>
17
18
19 <p>As of the release of XMLUnit 1.1 the
20 <code class="literal">Document</code> instances created by most parsers
21 implement <code class="literal">DocumentTraversal</code>, this includes
22 but is not limited to Apache Xerces, the parser shipping with
23 Sun's JDK 5 and later or GNU JAXP. One notable exception is
24 Apache Crimson, which also means the parser shipping with Sun's
25 JDK 1.4 does not support traversal; you need to specify a
26 different parser when using JDK 1.4 (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a>).</p>
27
28 <p>You can test whether your XML parser supports
29 <code class="literal">DocumentTraversal</code> by invoking
30 <code class="literal">org.w3c.dom.DOMImplementation</code>'s
31 <code class="literal">hasFeature</code> method with the feature
32 <code class="literal">"Traversal"</code>.</p>
33 </div>
34
35 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="NodeTest"></a>6.2. <code class="literal">NodeTest</code></h3></div></div></div>
36
37
38 <p>The <code class="literal">NodeTest</code> is instantiated with a
39 piece of XML to traverse. It offers two
40 <code class="literal">performTest</code> methods:</p>
41
42 <pre class="programlisting">
43 /**
44 * Does this NodeTest pass using the specified NodeTester instance?
45 * @param tester
46 * @param singleNodeType note &lt;code&gt;Node.ATTRIBUTE_NODE&lt;/code&gt; is not
47 * exposed by the DocumentTraversal node iterator unless the root node
48 * is itself an attribute - so a NodeTester that needs to test attributes
49 * should obtain those attributes from &lt;code&gt;Node.ELEMENT_NODE&lt;/code&gt;
50 * nodes
51 * @exception NodeTestException if test fails
52 */
53 public void performTest(NodeTester tester, short singleNodeType);
54
55 /**
56 * Does this NodeTest pass using the specified NodeTester instance?
57 * @param tester
58 * @param nodeTypes note &lt;code&gt;Node.ATTRIBUTE_NODE&lt;/code&gt; is not
59 * exposed by the DocumentTraversal node iterator unless the root node
60 * is itself an attribute - so a NodeTester that needs to test attributes
61 * should obtain those attributes from &lt;code&gt;Node.ELEMENT_NODE&lt;/code&gt;
62 * nodes instead
63 * @exception NodeTestException if test fails
64 */
65 public void performTest(NodeTester tester, short[] nodeTypes);
66 </pre>
67
68 <p><code class="literal">NodeTester</code> is the class testing each
69 node and is described in the next section.</p>
70
71 <p>The second argument limits the tests on DOM
72 <code class="literal">Node</code>s of (a) specific type(s).
73 <code class="literal">Node</code> types are specified via the
74 <code class="literal">static</code> fields of the <code class="literal">Node</code>
75 class. Any <code class="literal">Node</code> of a type not specified as
76 the second argument to <code class="literal">performTest</code> will be
77 ignored.</p>
78
79 <p>Unfortunately XML attributes are not exposed as
80 <code class="literal">Node</code>s during traversal. If you need access
81 to attributes you must add <code class="literal">Node.ELEMENT_NODE</code>
82 to the second argument of <code class="literal">performTest</code> and
83 access the attributes from their parent
84 <code class="literal">Element</code>.</p>
85
86 <div class="example"><a name="nodetest-attributes"></a><p class="title"><b>Example 33. Accessing Attributes in a
87 <code class="literal">NodeTest</code></b></p><div class="example-contents">
88
89 <pre class="programlisting">
90 ...
91 NodeTest nt = new NodeTest(myXML);
92 NodeTester tester = new MyNodeTester();
93 nt.performTest(tester, Node.ELEMENT_NODE);
94 ...
95
96 class MyNodeTester implements NodeTester {
97 public void testNode(Node aNode, NodeTest test) {
98 Element anElement = (Element) aNode;
99 Attr attributeToTest = anElement.getAttributeNode(ATTRIBUTE_NAME);
100 ...
101 }
102 ...
103 }
104 </pre></div></div><br class="example-break">
105
106 <p>Any entities that appear as part of the
107 <code class="literal">Document</code> are expanded before the traversal
108 starts.</p>
109
110 </div>
111
112 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="NodeTester"></a>6.3. NodeTester</h3></div></div></div>
113
114
115 <p>Implementations of the <code class="literal">NodeTester</code>
116 interface are responsible for the actual test:</p>
117
118 <pre class="programlisting">
119 /**
120 * Validate a single Node
121 * @param aNode
122 * @param forTest
123 * @exception NodeTestException if the node fails the test
124 */
125 void testNode(Node aNode, NodeTest forTest) throws NodeTestException ;
126
127 /**
128 * Validate that the Nodes passed one-by-one to the &lt;code&gt;testNode&lt;/code&gt;
129 * method were all the Nodes expected.
130 * @param forTest
131 * @exception NodeTestException if this instance was expecting more nodes
132 */
133 void noMoreNodes(NodeTest forTest) throws NodeTestException ;
134 </pre>
135
136 <p><code class="literal">NodeTest</code> invokes
137 <code class="literal">testNode</code> for each <code class="literal">Node</code> as
138 soon as it is reached on the traversal. This means
139 <code class="literal">NodeTester</code> "sees" the
140 <code class="literal">Node</code>s in the same order they appear within
141 the tree.</p>
142
143 <p><code class="literal">noMoreNodes</code> is invoked when the
144 traversal is finished. It will also be invoked if the tree didn't
145 contain any matched <code class="literal">Node</code>s at all.</p>
146
147 <p>Implementations of <code class="literal">NodeTester</code> are
148 expected to throw a <code class="literal">NodeTestException</code> if the
149 current not doesn't match the test's expectations or more nodes
150 have been expected when <code class="literal">noMoreNodes</code> is
151 called.</p>
152
153 <p>XMLUnit ships with two implementations of
154 <code class="literal">NodeTest</code> that are described in the following
155 to sections.</p>
156
157 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="AbstractNodeTester"></a>6.3.1. <code class="literal">AbstractNodeTester</code></h4></div></div></div>
158
159
160 <p><code class="literal">AbstractNodeTester</code> implements
161 <code class="literal">testNode</code> by testing the passed in
162 <code class="literal">Node</code> for its type and delegating to one of
163 the more specific <code class="literal">test...</code> Methods it adds.
164 By default the new <code class="literal">test...</code> methods all
165 throw a <code class="literal">NodeTestException</code> because of an
166 unexpected <code class="literal">Node</code>.</p>
167
168 <p>It further implements <code class="literal">noMoreNodes</code>
169 with an empty method - i.e. it does nothing.</p>
170
171 <p>If you are only testing for specific types of
172 <code class="literal">Node</code> it may be more convenient to subclass
173 <code class="literal">AbstractNodeTester</code>. For example <a class="xref" href="ar01s06.html#nodetest-attributes" title="Example 33. Accessing Attributes in a NodeTest">Example 33, &#8220;Accessing Attributes in a
174 <code class="literal">NodeTest</code>&#8221;</a> could be re-written as:</p>
175
176 <div class="example"><a name="idp43404032"></a><p class="title"><b>Example 34. Accessing Attributes in a
177 <code class="literal">NodeTest</code> -
178 <code class="literal">AbstractNodeTester</code> version</b></p><div class="example-contents">
179
180 <pre class="programlisting">
181 ...
182 NodeTest nt = new NodeTest(myXML);
183 NodeTester tester = new AbstractNodeTester() {
184 public void testElement(Element element) throws NodeTestException {
185 Attr attributeToTest = element.getAttributeNode(ATTRIBUTE_NAME);
186 ...
187 }
188 };
189 nt.performTest(tester, Node.ELEMENT_NODE);
190 ...
191 </pre></div></div><br class="example-break">
192
193 <p>Note that even though
194 <code class="literal">AbstractNodeTester</code> contains a
195 <code class="literal">testAttribute</code> method it will never be
196 called by default and you still need to access attributes via
197 their parent elements.</p>
198
199 <p>Note also that the root of the test is the document's
200 root element, so any <code class="literal">Node</code>s preceding the
201 document's root <code class="literal">Element</code> won't be visited
202 either. For this reason the
203 <code class="literal">testDocumentType</code>,
204 <code class="literal">testEntity</code> and
205 <code class="literal">testNotation</code> methods are probably never
206 called either.</p>
207
208 <p>Finally, all entity references have been expanded before
209 the traversal started. <code class="literal">EntityReference</code>s
210 will have been replaced by their replacement text if it is
211 available, which means <code class="literal">testEntityReference</code>
212 will not be called for them either. Instead the replacement
213 text will show up as (part of) a <code class="literal">Text</code> node
214 or as <code class="literal">Element</code> node, depending on the
215 entity's definition.</p>
216 </div>
217
218 <div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="CountingNodeTester"></a>6.3.2. <code class="literal">CountingNodeTester</code></h4></div></div></div>
219
220
221 <p><code class="literal">org.custommonkey.xmlunit.examples.CountingNodeTester</code>
222 is a simple example <code class="literal">NodeTester</code> that asserts
223 that a given number of <code class="literal">Node</code>s have been
224 traversed. It will throw a
225 <code class="literal">NodeTestException</code> when
226 <code class="literal">noMoreNodes</code> is called before the expected
227 number of <code class="literal">Node</code>s has been visited or the
228 actual number of nodes exceeded the expected count.</p>
229 </div>
230 </div>
231
232 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DOM%20Tree:%20JUnit%203"></a>6.4. JUnit 3.x Convenience Methods</h3></div></div></div>
233
234
235 <p><code class="literal">XMLAssert</code> and
236 <code class="literal">XMLTestCase</code> contain overloads of
237 <code class="literal">assertNodeTestPasses</code> methods.</p>
238
239 <p>The most general form of it expects you to create a
240 <code class="literal">NodeTest</code> instance yourself and lets you
241 specify whether you expect the test to fail or to pass.</p>
242
243 <p>The other two overloads create a
244 <code class="literal">NodeTest</code> instance from either
245 <code class="literal">String</code> or a SAX
246 <code class="literal">InputSource</code> and are specialized for the case
247 where you are only interested in a single <code class="literal">Node</code>
248 type and expect the test to pass.</p>
249
250 <p>Neither method provides any control over the message of
251 the <code class="literal">AssertionFailedError</code> in case of a
252 failure.</p>
253 </div>
254
255 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DOM%20Tree:%20Configuration"></a>6.5. Configuration Options</h3></div></div></div>
256
257
258 <p>The only configurable option for
259 <code class="literal">NodeTest</code> is the XML parser used if the piece
260 of XML is not specified as a <code class="literal">Document</code> or
261 <code class="literal">DocumentTraversal</code>.
262 <code class="literal">NodeTest</code> will use the "control" parser that
263 has been configured - see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a> for
264 details.</p>
265
266 <p>It will also use the <code class="literal">EntityResolver</code>
267 configured for the control parser if one has been set - see
268 <a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2. EntityResolver">Section 2.4.2, &#8220;<code class="literal">EntityResolver</code>&#8221;</a>.</p>
269 </div>
270
271 </div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="apa.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. XPath Tests </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A. Changes</td></tr></table></div></body></html>
0 <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>XMLUnit Java User's Guide</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="next" href="ar01s02.html" title="2. Using XMLUnit"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">XMLUnit Java User's Guide</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr></table><hr></div><div class="article"><div class="titlepage"><div><div><h2 class="title"><a name="idp42282464"></a>XMLUnit Java User's Guide</h2></div><div><div class="authorgroup">
1 <div class="author"><h3 class="author"><span class="firstname">Tim</span> <span class="surname">Bacon</span></h3></div>
2 <div class="author"><h3 class="author"><span class="firstname">Stefan</span> <span class="surname">Bodewig</span></h3></div>
3 </div></div><div><div class="revhistory"><table style="border-style:solid; width:100%;" summary="Revision History"><tr><th align="left" valign="top" colspan="3"><b>Revision History</b></th></tr>
4 <tr><td align="left">Revision 1.0</td><td align="left">January 2003</td><td align="left">
5 <span class="firstname">Tim<br></span>
6 <span class="surname">Bacon<br></span>
7 </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.0</td></tr>
8 <tr><td align="left">Revision 1.1</td><td align="left">April 2007</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.1</td></tr>
9 <tr><td align="left">Revision 1.2</td><td align="left">June 2008</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.2</td></tr>
10 <tr><td align="left">Revision 1.3</td><td align="left">September 2009</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.3</td></tr>
11 <tr><td align="left">Revision 1.4</td><td align="left">February 2013</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.4</td></tr>
12 <tr><td align="left">Revision 1.5</td><td align="left">September 2013</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.5</td></tr>
13 <tr><td align="left">Revision 1.6</td><td align="left">December 2014</td><td> </td></tr><tr><td align="left" colspan="3">Documentation for XMLUnit Java 1.6</td></tr>
14 </table></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="index.html#A%20Tour%20of%20XMLUnit">1. A Tour of XMLUnit</a></span></dt><dd><dl><dt><span class="section"><a href="index.html#What%20is%20XMLUnit?">1.1. What is XMLUnit?</a></span></dt><dt><span class="section"><a href="index.html#Quick%20Tour">1.2. Quick tour</a></span></dt><dt><span class="section"><a href="index.html#Glossary">1.3. Glossary</a></span></dt><dt><span class="section"><a href="index.html#Configuring%20XMLUnit">1.4. Configuring XMLUnit</a></span></dt><dt><span class="section"><a href="index.html#Writing%20XML%20comparison%20tests">1.5. Writing XML comparison tests</a></span></dt><dt><span class="section"><a href="index.html#Comparing%20XML%20Transformations">1.6. Comparing XML Transformations</a></span></dt><dt><span class="section"><a href="index.html#Validation%20Tests">1.7. Validation Tests</a></span></dt><dt><span class="section"><a href="index.html#Xpath%20Tests">1.8. XPath Tests</a></span></dt><dt><span class="section"><a href="index.html#Testing%20by%20Tree%20Walking">1.9. Testing by Tree Walking</a></span></dt></dl></dd><dt><span class="section"><a href="ar01s02.html">2. Using XMLUnit</a></span></dt><dd><dl><dt><span class="section"><a href="ar01s02.html#Requirements">2.1. Requirements</a></span></dt><dt><span class="section"><a href="ar01s02.html#Basic%20Usage">2.2. Basic Usage</a></span></dt><dt><span class="section"><a href="ar01s02.html#Using%20XMLUnit%20With%20JUnit%203.x">2.3. Using XMLUnit With JUnit 3.x</a></span></dt><dt><span class="section"><a href="ar01s02.html#Common%20Configuration%20Options">2.4. Common Configuration Options</a></span></dt><dt><span class="section"><a href="ar01s02.html#Providing%20Input%20to%20XMLUnit">2.5. Providing Input to XMLUnit</a></span></dt></dl></dd><dt><span class="section"><a href="ar01s03.html">3. Comparing Pieces of XML</a></span></dt><dd><dl><dt><span class="section"><a href="ar01s03.html#The%20Difference%20Engine">3.1. The Difference Engine</a></span></dt><dt><span class="section"><a href="ar01s03.html#ComparisonController">3.2. <code class="literal">ComparisonController</code></a></span></dt><dt><span class="section"><a href="ar01s03.html#DifferenceListener">3.3. <code class="literal">DifferenceListener</code></a></span></dt><dt><span class="section"><a href="ar01s03.html#ElementQualifier">3.4. <code class="literal">ElementQualifier</code></a></span></dt><dt><span class="section"><a href="ar01s03.html#Diff">3.5. <code class="literal">Diff</code> and
15 <code class="literal">DetailedDiff</code></a></span></dt><dt><span class="section"><a href="ar01s03.html#MatchTracker">3.6. <code class="literal">MatchTracker</code></a></span></dt><dt><span class="section"><a href="ar01s03.html#Comparing:%20JUnit%203">3.7. JUnit 3.x Convenience Methods</a></span></dt><dt><span class="section"><a href="ar01s03.html#Comparing:%20Configuration">3.8. Configuration Options</a></span></dt></dl></dd><dt><span class="section"><a href="ar01s04.html">4. Validating XML Documents</a></span></dt><dd><dl><dt><span class="section"><a href="ar01s04.html#The%20Validator%20Class">4.1. The <code class="literal">Validator</code> Class</a></span></dt><dt><span class="section"><a href="ar01s04.html#Validation:%20JUnit%203">4.2. JUnit 3.x Convenience Methods</a></span></dt><dt><span class="section"><a href="ar01s04.html#Validation:%20Configuration">4.3. Configuration Options</a></span></dt><dt><span class="section"><a href="ar01s04.html#JAXP%201.3%20Validation">4.4. JAXP 1.3 Validation</a></span></dt></dl></dd><dt><span class="section"><a href="ar01s05.html">5. XPath Tests</a></span></dt><dd><dl><dt><span class="section"><a href="ar01s05.html#XPath%20Engines">5.1. XPath Engines</a></span></dt><dt><span class="section"><a href="ar01s05.html#Using%20XML%20Namespaces%20in%20XPath%20Selectors">5.2. Using XML Namespaces in XPath Selectors</a></span></dt><dt><span class="section"><a href="ar01s05.html#XPath:%20JUnit%203">5.3. JUnit 3.x Convenience Methods</a></span></dt><dt><span class="section"><a href="ar01s05.html#XPath:%20Configuration">5.4. Configuration Options</a></span></dt></dl></dd><dt><span class="section"><a href="ar01s06.html">6. DOM Tree Walking</a></span></dt><dd><dl><dt><span class="section"><a href="ar01s06.html#DocumentTraversal">6.1. <code class="literal">DocumentTraversal</code></a></span></dt><dt><span class="section"><a href="ar01s06.html#NodeTest">6.2. <code class="literal">NodeTest</code></a></span></dt><dt><span class="section"><a href="ar01s06.html#NodeTester">6.3. NodeTester</a></span></dt><dt><span class="section"><a href="ar01s06.html#DOM%20Tree:%20JUnit%203">6.4. JUnit 3.x Convenience Methods</a></span></dt><dt><span class="section"><a href="ar01s06.html#DOM%20Tree:%20Configuration">6.5. Configuration Options</a></span></dt></dl></dd><dt><span class="appendix"><a href="apa.html">A. Changes</a></span></dt><dd><dl><dt><span class="section"><a href="apa.html#Changes%201.1">A.1. Changes from XMLUnit 1.0 to 1.1</a></span></dt><dd><dl><dt><span class="section"><a href="apa.html#Breaking%20Changes%201.1">A.1.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apa.html#New%20Features%201.1">A.1.2. New Features</a></span></dt><dt><span class="section"><a href="apa.html#Bugfixes%201.1">A.1.3. Important Bug Fixes</a></span></dt></dl></dd><dt><span class="section"><a href="apas02.html">A.2. Changes from XMLUnit 1.1 to 1.2</a></span></dt><dd><dl><dt><span class="section"><a href="apas02.html#Breaking%20Changes%201.2">A.2.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apas02.html#New%20Features%201.2">A.2.2. New Features</a></span></dt><dt><span class="section"><a href="apas02.html#Bugfixes%201.2">A.2.3. Important Bug Fixes</a></span></dt></dl></dd><dt><span class="section"><a href="apas03.html">A.3. Changes from XMLUnit 1.2 to 1.3</a></span></dt><dd><dl><dt><span class="section"><a href="apas03.html#Breaking%20Changes%201.3">A.3.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apas03.html#New%20Features%201.3">A.3.2. New Features</a></span></dt><dt><span class="section"><a href="apas03.html#Bugfixes%201.3">A.3.3. Important Bug Fixes</a></span></dt></dl></dd><dt><span class="section"><a href="apas04.html">A.4. Changes from XMLUnit 1.3 to 1.4</a></span></dt><dd><dl><dt><span class="section"><a href="apas04.html#Breaking%20Changes%201.4">A.4.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apas04.html#New%20Features%201.4">A.4.2. New Features</a></span></dt><dt><span class="section"><a href="apas04.html#Bugfixes%201.4">A.4.3. Important Bug Fixes</a></span></dt></dl></dd><dt><span class="section"><a href="apas05.html">A.5. Changes from XMLUnit 1.4 to 1.5</a></span></dt><dd><dl><dt><span class="section"><a href="apas05.html#Breaking%20Changes%201.5">A.5.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apas05.html#New%20Features%201.5">A.5.2. New Features</a></span></dt><dt><span class="section"><a href="apas05.html#Bugfixes%201.5">A.5.3. Important Bug Fixes</a></span></dt></dl></dd><dt><span class="section"><a href="apas06.html">A.6. Changes from XMLUnit 1.5 to 1.6</a></span></dt><dd><dl><dt><span class="section"><a href="apas06.html#Breaking%20Changes%201.6">A.6.1. Breaking Changes</a></span></dt><dt><span class="section"><a href="apas06.html#New%20Features%201.6">A.6.2. New Features</a></span></dt><dt><span class="section"><a href="apas06.html#Bugfixes%201.6">A.6.3. Important Bug Fixes</a></span></dt></dl></dd></dl></dd></dl></div>
16
17
18
19 <div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="A%20Tour%20of%20XMLUnit"></a>1. A Tour of XMLUnit</h2></div></div></div>
20
21 <p>This first section contains a tour through XMLUnit's
22 features, the next sections will cover them in more detail.</p>
23
24 <p>Note that it has a strong focus on using the
25 <code class="literal">XMLTestCase</code> class which is one option to use
26 XMLUnit, but not the only one. XMLUnit's features can be fully
27 used without any dependency on JUnit at all.</p>
28
29 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="What%20is%20XMLUnit?"></a>1.1. What is XMLUnit?</h3></div></div></div>
30
31 <p>XMLUnit enables JUnit-style assertions to be made about
32 the content and structure of XML<a href="#ftn.more%20on%20JUnit" class="footnote" name="more%20on%20JUnit"><sup class="footnote">[1]</sup></a>. It
33 is an open source project hosted at <a class="ulink" href="http://xmlunit.sourceforge.net/" target="_top">http://xmlunit.sourceforge.net/</a>
34 that grew out of a need to test a system that generated and
35 received custom XML messages. The problem that we faced was how
36 to verify that the system generated the correct message from a
37 known set of inputs. Obviously we could use a DTD or a schema to
38 validate the message output, but this approach wouldn't allow us
39 to distinguish between valid XML with correct content (e.g.
40 element <code class="literal">&lt;foo&gt;bar&lt;/foo&gt;</code>) and valid
41 XML with incorrect content (e.g. element
42 <code class="literal">&lt;foo&gt;baz&lt;/foo&gt;</code>). What we really
43 wanted was an <code class="literal">assertXMLEqual()</code> method, so we
44 could compare the message that we expected the system to
45 generate and the message that the system actually generated. And
46 that was the beginning of XMLUnit.</p>
47 </div>
48 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Quick%20Tour"></a>1.2. Quick tour</h3></div></div></div>
49
50 <p>XMLUnit provides a single JUnit extension class,
51 <code class="literal">XMLTestCase</code>, and a set of supporting classes
52 that allow assertions to be made about:</p>
53
54 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The differences between two pieces of XML (via
55 <code class="literal">Diff</code> and <code class="literal">DetailedDiff</code>
56 classes)</li><li class="listitem">The validity of a piece of XML (via
57 <code class="literal">Validator</code> class)</li><li class="listitem"> The outcome of transforming a piece of XML using
58 XSLT (via <code class="literal">Transform</code> class)</li><li class="listitem">The evaluation of an XPath expression on a piece of
59 XML (via classes implementing the
60 <code class="literal">XpathEngine</code> interface)</li><li class="listitem">Individual nodes in a piece of XML that are exposed
61 by DOM Traversal (via <code class="literal">NodeTest</code>
62 class)</li></ul></div>
63
64 <p>XMLUnit can also treat HTML content, even badly-formed
65 HTML, as valid XML to allow these assertions to be made about
66 web pages (via the <code class="literal">HTMLDocumentBuilder</code>
67 class).</p>
68 </div>
69
70 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Glossary"></a>1.3. Glossary</h3></div></div></div>
71
72 <p>As with many projects some words in XMLUnit have
73 particular meanings so here is a quick overview. A
74 <span class="emphasis"><em>piece</em></span> of XML is a DOM Document, a String
75 containing marked-up content, or a Source or Reader that allows
76 access to marked-up content within some resource. XMLUnit
77 compares the expected <span class="emphasis"><em>control</em></span> XML to some
78 actual <span class="emphasis"><em>test</em></span> XML. The comparison can reveal
79 that two pieces of XML are <span class="emphasis"><em>identical</em></span>,
80 <span class="emphasis"><em>similar</em></span> or
81 <span class="emphasis"><em>different</em></span>. The unit of measurement used by
82 the comparison is a <span class="emphasis"><em>difference</em></span>, and
83 differences can be either <span class="emphasis"><em>recoverable</em></span> or
84 <span class="emphasis"><em>unrecoverable</em></span>. Two pieces of XML are
85 <span class="emphasis"><em>identical</em></span> if there are <span class="emphasis"><em>no
86 differences</em></span> between them,
87 <span class="emphasis"><em>similar</em></span> if there are <span class="emphasis"><em>only
88 recoverable differences</em></span> between them, and
89 <span class="emphasis"><em>different</em></span> if there are <span class="emphasis"><em>any
90 unrecoverable differences</em></span> between them.</p>
91 </div>
92
93 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Configuring%20XMLUnit"></a>1.4. Configuring XMLUnit</h3></div></div></div>
94
95 <p>There are many Java XML parsers available, and XMLUnit
96 should work with any JAXP compliant parser library, such as
97 Xerces-J <a href="#ftn.xerces-link" class="footnote" name="xerces-link"><sup class="footnote">[2]</sup></a>
98 from the Apache Software Foundation. To use the XSLT and XPath
99 features of XMLUnit a Trax (the XSLT portion of JAXP) compliant
100 transformation engine is required, such as Xalan-J<a href="#ftn.xalan-link" class="footnote" name="xalan-link"><sup class="footnote">[3]</sup></a>,
101 from the Apache Software Foundation. To configure XMLUnit to
102 use a specific parser and transformation engine set three System
103 properties before any tests are run, e.g.</p>
104
105 <div class="example"><a name="idp42377776"></a><p class="title"><b>Example 1. Configuring JAXP via System Properties</b></p><div class="example-contents">
106 <pre class="programlisting">
107 System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
108 "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
109 System.setProperty("javax.xml.parsers.SAXParserFactory",
110 "org.apache.xerces.jaxp.SAXParserFactoryImpl");
111 System.setProperty("javax.xml.transform.TransformerFactory",
112 "org.apache.xalan.processor.TransformerFactoryImpl");
113 </pre>
114 </div></div><br class="example-break">
115
116 <p>You may want to read <a class="xref" href="ar01s02.html#JAXP" title="2.4.1. JAXP">Section 2.4.1, &#8220;JAXP&#8221;</a> for more
117 details - in particular if you are using Java 1.4 or
118 later.</p>
119
120 <p>Alternatively there are static methods on the XMLUnit
121 class that can be called directly. The advantage of this
122 approach is that you can specify a different parser class for
123 control and test XML and change the current parser class at any
124 time in your tests, should you need to make assertions about the
125 compatibility of different parsers.</p>
126
127 <div class="example"><a name="idp42381296"></a><p class="title"><b>Example 2. Configuring JAXP via XMLUnit class</b></p><div class="example-contents">
128 <pre class="programlisting">
129 XMLUnit.setControlParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
130 XMLUnit.setTestParser("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
131 XMLUnit.setSAXParserFactory("org.apache.xerces.jaxp.SAXParserFactoryImpl");
132 XMLUnit.setTransformerFactory("org.apache.xalan.processor.TransformerFactoryImpl");
133 </pre>
134 </div></div><br class="example-break">
135
136 </div>
137
138 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Writing%20XML%20comparison%20tests"></a>1.5. Writing XML comparison tests</h3></div></div></div>
139
140
141 <p>Let's say we have two pieces of XML that we wish to
142 compare and assert that they are equal. We could write a simple
143 test class like this:</p>
144
145 <div class="example"><a name="idp42385216"></a><p class="title"><b>Example 3. A simple comparison test</b></p><div class="example-contents">
146 <pre class="programlisting">
147 public class MyXMLTestCase extends XMLTestCase {
148 public MyXMLTestCase(String name) {
149 super(name);
150 }
151
152 public void testForEquality() throws Exception {
153 String myControlXML = "&lt;msg&gt;&lt;uuid&gt;0x00435A8C&lt;/uuid&gt;&lt;/msg&gt;";
154 String myTestXML = "&lt;msg&gt;&lt;localId&gt;2376&lt;/localId&gt;&lt;/msg&gt;";
155 assertXMLEqual("Comparing test xml to control xml",
156 myControlXML, myTestXML);
157 }
158 }</pre></div></div><br class="example-break">
159
160 <p>The <code class="literal">assertXMLEqual</code> test will pass if
161 the control and test XML are either similar or
162 identical. Obviously in this case the pieces of XML are
163 different and the test will fail. The failure message indicates
164 both what the difference is and the XPath locations of the nodes
165 that were being compared:</p>
166
167 <pre class="programlisting">
168 Comparing test xml to control xml
169 [different] Expected element tag name 'uuid' but was 'localId' - comparing &lt;uuid...&gt; at /msg[1]/uuid[1] to &lt;localId...&gt; at /msg[1]/localId[1]
170 </pre>
171
172 <p>When comparing pieces of XML, the
173 <code class="literal">XMLTestCase</code> actually creates an instance of
174 the <code class="literal">Diff</code> class. The <code class="literal">Diff</code>
175 class stores the result of an XML comparison and makes it
176 available through the methods <code class="literal">similar()</code> and
177 <code class="literal">identical()</code>. The
178 <code class="literal">assertXMLEqual()</code> method tests the value of
179 <code class="literal">Diff.similar()</code> and the
180 <code class="literal">assertXMLIdentical()</code> method tests the value
181 of <code class="literal">Diff.identical()</code>.</p>
182
183 <p>It is easy to create a <code class="literal">Diff</code> instance
184 directly without using the <code class="literal">XMLTestCase</code> class
185 as below:</p>
186
187 <div class="example"><a name="idp42397472"></a><p class="title"><b>Example 4. Creating a <code class="literal">Diff</code>
188 instance</b></p><div class="example-contents">
189 <pre class="programlisting">
190 public void testXMLIdentical()throws Exception {
191 String myControlXML =
192 "&lt;struct&gt;&lt;int&gt;3&lt;/int&gt;&lt;boolean&gt;false&lt;/boolean&gt;&lt;/struct&gt;";
193 String myTestXML =
194 "&lt;struct&gt;&lt;boolean&gt;false&lt;/boolean&gt;&lt;int&gt;3&lt;/int&gt;&lt;/struct&gt;";
195 Diff myDiff = new Diff(myControlXML, myTestXML);
196 assertTrue("XML similar " + myDiff.toString(),
197 myDiff.similar());
198 assertTrue("XML identical " + myDiff.toString(),
199 myDiff.identical());
200 }</pre></div></div><br class="example-break">
201
202 <p>This test fails as two pieces of XML are similar but not
203 identical if their nodes occur in a different sequence. The
204 failure message reported by JUnit from the call to
205 <code class="literal">myDiff.toString()</code> looks like this:</p>
206
207 <pre class="programlisting">
208 [not identical] Expected sequence of child nodes '0' but was '1' - comparing &lt;int...&gt; at /struct[1]/int[1] to &lt;int...&gt; at /struct[1]/int[1]
209 </pre>
210
211 <p>For efficiency reasons a <code class="literal">Diff</code> stops the
212 comparison process as soon as the first difference is found. To
213 get all the differences between two pieces of XML an instance of
214 the <code class="literal">DetailedDiff</code> class, a subclass of
215 <code class="literal">Diff</code>, is required. Note that a
216 <code class="literal">DetailedDiff</code> is constructed using an existing
217 <code class="literal">Diff</code> instance.</p>
218
219 <p>Consider this test that uses a DetailedDiff:</p>
220
221 <div class="example"><a name="idp42407472"></a><p class="title"><b>Example 5. Using <code class="literal">DetailedDiff</code></b></p><div class="example-contents">
222 <pre class="programlisting">
223 public void testAllDifferences() throws Exception {
224 String myControlXML = "&lt;news&gt;&lt;item id=\"1\"&gt;War&lt;/item&gt;"
225 + "&lt;item id=\"2\"&gt;Plague&lt;/item&gt;"
226 + "&lt;item id=\"3\"&gt;Famine&lt;/item&gt;&lt;/news&gt;";
227 String myTestXML = "&lt;news&gt;&lt;item id=\"1\"&gt;Peace&lt;/item&gt;"
228 + "&lt;item id=\"2\"&gt;Health&lt;/item&gt;"
229 + "&lt;item id=\"3\"&gt;Plenty&lt;/item&gt;&lt;/news&gt;";
230 DetailedDiff myDiff = new DetailedDiff(new Diff(myControlXML, myTestXML));
231 List allDifferences = myDiff.getAllDifferences();
232 assertEquals(myDiff.toString(), 2, allDifferences.size());
233 }</pre></div></div><br class="example-break">
234
235 <p>This test fails with the message below as each of the 3
236 news items differs between the control and test XML:</p>
237
238 <pre class="programlisting">
239 [different] Expected text value 'War' but was 'Peace' - comparing &lt;item...&gt;War&lt;/item&gt; at /news[1]/item[1]/text()[1] to &lt;item...&gt;Peace&lt;/item&gt; at /news[1]/item[1]/text()[1]
240 [different] Expected text value 'Plague' but was 'Health' - comparing &lt;item...&gt;Plague&lt;/item&gt; at /news[1]/item[2]/text()[1] to &lt;item...&gt;Health&lt;/item&gt; at /news[1]/item[2]/text()[1]
241 [different] Expected text value 'Famine' but was 'Plenty' - comparing &lt;item...&gt;Famine&lt;/item&gt; at /news[1]/item[3]/text()[1] to &lt;item...&gt;Plenty&lt;/item&gt; at /news[1]/item[3]/text()[1]
242 expected &lt;2&gt; but was &lt;3&gt;
243 </pre>
244
245 <p>The List returned from the
246 <code class="literal">getAllDifferences()</code> method contains
247 <code class="literal">Difference</code> instances. These instances
248 describe both the type<a href="#ftn.DifferenceConstants" class="footnote" name="DifferenceConstants"><sup class="footnote">[4]</sup></a> of difference found between a control
249 node and test node and the <code class="literal">NodeDetail</code> of
250 those nodes (including the XPath location of each
251 node). <code class="literal">Difference</code> instances are passed at
252 runtime in notification events to a registered
253 <code class="literal">DifferenceListener</code>, an interface whose
254 default implementation is provided by the
255 <code class="literal">Diff</code> class.</p>
256
257 <p>However it is possible to override this default behaviour
258 by implementing the interface in your own class. The
259 <code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code>
260 class is an example of how to implement a custom
261 <code class="literal">DifferenceListener</code>. It allows an XML
262 comparison to be made that ignores differences in the values of
263 text and attribute nodes, for example when comparing a skeleton
264 or outline piece of XML to some generated XML.</p>
265
266 <p>The following test illustrates the use of a custom
267 <code class="literal">DifferenceListener</code>:</p>
268
269 <div class="example"><a name="idp42422960"></a><p class="title"><b>Example 6. Using a custom
270 <code class="literal">DifferenceListener</code></b></p><div class="example-contents">
271 <pre class="programlisting">
272 public void testCompareToSkeletonXML() throws Exception {
273 String myControlXML = "&lt;location&gt;&lt;street-address&gt;22 any street&lt;/street-address&gt;&lt;postcode&gt;XY00 99Z&lt;/postcode&gt;&lt;/location&gt;";
274 String myTestXML = "&lt;location&gt;&lt;street-address&gt;20 east cheap&lt;/street-address&gt;&lt;postcode&gt;EC3M 1EB&lt;/postcode&gt;&lt;/location&gt;";
275 DifferenceListener myDifferenceListener = new IgnoreTextAndAttributeValuesDifferenceListener();
276 Diff myDiff = new Diff(myControlXML, myTestXML);
277 myDiff.overrideDifferenceListener(myDifferenceListener);
278 assertTrue("test XML matches control skeleton XML",
279 myDiff.similar());
280 }</pre></div></div><br class="example-break">
281
282 <p>The <code class="literal">DifferenceEngine</code> class generates
283 the events that are passed to a
284 <code class="literal">DifferenceListener</code> implementation as two
285 pieces of XML are compared. Using recursion it navigates through
286 the nodes in the control XML DOM, and determines which node in
287 the test XML DOM qualifies for comparison to the current control
288 node. The qualifying test node will match the control node's
289 node type, as well as the node name and namespace (if defined
290 for the control node).</p>
291
292 <p>However when the control node is an
293 <code class="literal">Element</code>, it is less straightforward to
294 determine which test <code class="literal">Element</code> qualifies for
295 comparison as the parent node may contain repeated child
296 <code class="literal">Element</code>s with the same name and namespace. So
297 for <code class="literal">Element</code> nodes, an instance of the
298 <code class="literal">ElementQualifier</code> interface is used determine
299 whether a given test <code class="literal">Element</code> node qualifies
300 for comparison with a control <code class="literal">Element</code>
301 node. This separates the decision about whether two
302 <code class="literal">Elements</code> should be compared from the decision
303 about whether those two <code class="literal">Elements</code> are
304 considered similar. By default an
305 <code class="literal">ElementNameQualifier</code> class is used that
306 compares the nth child <code class="literal">&lt;abc&gt;</code> test
307 element to the nth child <code class="literal">&lt;abc&gt;</code>
308 control element, i.e. the sequence of the child elements in the
309 test XML is important. However this default behaviour can be
310 overridden using an
311 <code class="literal">ElementNameAndTextQualifier</code> or
312 <code class="literal">ElementNameAndAttributesQualifier</code>.</p>
313
314 <p>The test below demonstrates the use of a custom
315 <code class="literal">ElementQualifier</code>:</p>
316
317 <div class="example"><a name="idp42440864"></a><p class="title"><b>Example 7. Using a custom
318 <code class="literal">ElementQualifier</code></b></p><div class="example-contents">
319 <pre class="programlisting">
320 public void testRepeatedChildElements() throws Exception {
321 String myControlXML = "&lt;suite&gt;"
322 + "&lt;test status=\"pass\"&gt;FirstTestCase&lt;/test&gt;"
323 + "&lt;test status=\"pass\"&gt;SecondTestCase&lt;/test&gt;&lt;/suite&gt;";
324 String myTestXML = "&lt;suite&gt;"
325 + "&lt;test status=\"pass\"&gt;SecondTestCase&lt;/test&gt;"
326 + "&lt;test status=\"pass\"&gt;FirstTestCase&lt;/test&gt;&lt;/suite&gt;";
327 assertXMLNotEqual("Repeated child elements in different sequence order are not equal by default",
328 myControlXML, myTestXML);
329 Diff myDiff = new Diff(myControlXML, myTestXML);
330 myDiff.overrideElementQualifier(new ElementNameAndTextQualifier());
331 assertXMLEqual("But they are equal when an ElementQualifier controls which test element is compared with each control element",
332 myDiff, true);
333 }</pre></div></div><br class="example-break">
334
335 <p>Note: calling <code class="literal">toString</code> on an instance
336 of <code class="literal">Diff</code> or <code class="literal">DetailedDiff</code>
337 will perform the comparision and cache its result immediately.
338 If you change the <code class="literal">DifferenceListener</code> or
339 <code class="literal">ElementQualifier</code> after calling
340 <code class="literal">toString</code> it won't have any effect.</p>
341
342 </div>
343
344 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Comparing%20XML%20Transformations"></a>1.6. Comparing XML Transformations</h3></div></div></div>
345
346
347 <p>XMLUnit can test XSLT transformations at a high level using
348 the <code class="literal">Transform</code> class that wraps an
349 <code class="literal">javax.xml.transform.Transformer</code>
350 instance. Knowing the input XML, input stylesheet and expected
351 output XML we can assert that the output of the transformation
352 matches the expected output as follows:</p>
353
354 <div class="example"><a name="idp42451584"></a><p class="title"><b>Example 8. Testing the Result of a Transformation</b></p><div class="example-contents">
355 <pre class="programlisting">
356 public void testXSLTransformation() throws Exception {
357 String myInputXML = "...";
358 File myStylesheetFile = new File("...");
359 Transform myTransform = new Transform(myInputXML, myStylesheetFile);
360 String myExpectedOutputXML = "...";
361 Diff myDiff = new Diff(myExpectedOutputXML, myTransform);
362 assertTrue("XSL transformation worked as expected", myDiff.similar());
363 }</pre></div></div><br class="example-break">
364
365 <p>The <code class="literal">getResultString()</code> and
366 <code class="literal">getResultDocument()</code> methods of the
367 <code class="literal">Transform</code> class can be used to access the
368 result of the XSLT transformation programmatically if required,
369 for example as below:</p>
370
371 <div class="example"><a name="idp42456320"></a><p class="title"><b>Example 9. Using <code class="literal">Transform</code>
372 programmatically</b></p><div class="example-contents">
373 <pre class="programlisting">
374 public void testAnotherXSLTransformation() throws Exception {
375 File myInputXMLFile = new File("...");
376 File myStylesheetFile = new File("...");
377 Transform myTransform = new Transform(
378 new StreamSource(myInputXMLFile),
379 new StreamSource(myStylesheetFile));
380 Document myExpectedOutputXML =
381 XMLUnit.buildDocument(XMLUnit.getControlParser(),
382 new FileReader("..."));
383 Diff myDiff = new Diff(myExpectedOutputXML,
384 myTransform.getResultDocument());
385 assertTrue("XSL transformation worked as expected", myDiff.similar());
386 }</pre></div></div><br class="example-break">
387
388 </div>
389
390 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Validation%20Tests"></a>1.7. Validation Tests</h3></div></div></div>
391
392 <p>XML parsers that validate a piece of XML against a DTD are
393 common, however they rely on a DTD reference being present in
394 the XML, and they can only validate against a single DTD. When
395 writing a system that exchanges XML messages with third parties
396 there are times when you would like to validate the XML against
397 a DTD that is not available to the recipient of the message and
398 so cannot be referenced in the message itself. XMLUnit provides
399 a <code class="literal">Validator</code> class for this purpose.</p>
400
401 <div class="example"><a name="idp42461696"></a><p class="title"><b>Example 10. Validating Against a DTD</b></p><div class="example-contents">
402 <pre class="programlisting">
403 public void testValidation() throws Exception {
404 XMLUnit.getTestDocumentBuilderFactory().setValidating(true);
405 // As the document is parsed it is validated against its referenced DTD
406 Document myTestDocument = XMLUnit.buildTestDocument("...");
407 String mySystemId = "...";
408 String myDTDUrl = new File("...").toURL().toExternalForm();
409 Validator myValidator = new Validator(myTestDocument, mySystemId,
410 myDTDUrl);
411 assertTrue("test document validates against unreferenced DTD",
412 myValidator.isValid());
413 }</pre></div></div><br class="example-break">
414
415 <p>Starting with XMLUnit 1.1, the
416 <code class="literal">Validator</code> class can also validate against one
417 or more XML Schema definitions. See <a class="xref" href="ar01s04.html#XML%20Schema%20Validation" title="4.1.2. XML Schema Validation">Section 4.1.2, &#8220;XML Schema Validation&#8221;</a> for details.</p>
418
419 <p>XMLUnit 1.2 introduces a new <code class="literal">Validator</code>
420 class that relies on JAXP
421 1.3's <code class="literal">javax.xml.validation</code> package. This
422 Validator can validate against W3C XML Schema, but may support
423 different Schema languages like RELAX NG if your JAXP
424 implementation supports it. See
425 <a class="xref" href="ar01s04.html#JAXP%201.3%20Validation" title="4.4. JAXP 1.3 Validation">Section 4.4, &#8220;JAXP 1.3 Validation&#8221;</a> for details.</p>
426
427 </div>
428
429 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Xpath%20Tests"></a>1.8. XPath Tests</h3></div></div></div>
430
431 <p>One of the strengths of XML is the ability to
432 programmatically extract specific parts of a document using
433 XPath expressions. The <code class="literal">XMLTestCase</code> class
434 offers a number of XPath related assertion methods, as
435 demonstrated in this test:</p>
436
437 <div class="example"><a name="idp42470432"></a><p class="title"><b>Example 11. Using XPath Tests</b></p><div class="example-contents">
438 <pre class="programlisting">
439 public void testXPaths() throws Exception {
440 String mySolarSystemXML = "&lt;solar-system&gt;"
441 + "&lt;planet name='Earth' position='3' supportsLife='yes'/&gt;"
442 + "&lt;planet name='Venus' position='4'/&gt;&lt;/solar-system&gt;";
443 assertXpathExists("//planet[@name='Earth']", mySolarSystemXML);
444 assertXpathNotExists("//star[@name='alpha centauri']",
445 mySolarSystemXML);
446 assertXpathsEqual("//planet[@name='Earth']",
447 "//planet[@position='3']", mySolarSystemXML);
448 assertXpathsNotEqual("//planet[@name='Venus']",
449 "//planet[@supportsLife='yes']",
450 mySolarSystemXML);
451 }</pre></div></div><br class="example-break">
452
453 <p>When an XPath expression is evaluated against a piece of
454 XML a <code class="literal">NodeList</code> is created that contains the
455 matching <code class="literal">Node</code>s. The methods in the previous
456 test <code class="literal">assertXpathExists</code>,
457 <code class="literal">assertXpathNotExists</code>,
458 <code class="literal">assertXpathsEqual</code>, and
459 <code class="literal">assertXpathsNotEqual</code> use these
460 <code class="literal">NodeList</code>s. However, the contents of a
461 <code class="literal">NodeList</code> can be flattened (or
462 <code class="literal">String</code>-ified) to a single value, and XMLUnit
463 also allows assertions to be made about this single value, as in
464 this test<a href="#ftn.XpathEngine%20note" class="footnote" name="XpathEngine%20note"><sup class="footnote">[5]</sup></a>:</p>
465
466 <div class="example"><a name="idp42482144"></a><p class="title"><b>Example 12. Testing XPath Values</b></p><div class="example-contents">
467 <pre class="programlisting">
468 public void testXPathValues() throws Exception {
469 String myJavaFlavours = "&lt;java-flavours&gt;"
470 + "&lt;jvm current='some platforms'&gt;1.1.x&lt;/jvm&gt;"
471 + "&lt;jvm current='no'&gt;1.2.x&lt;/jvm&gt;"
472 + "&lt;jvm current='yes'&gt;1.3.x&lt;/jvm&gt;"
473 + "&lt;jvm current='yes' latest='yes'&gt;1.4.x&lt;/jvm&gt;&lt;/javaflavours&gt;";
474 assertXpathEvaluatesTo("2", "count(//jvm[@current='yes'])",
475 myJavaFlavours);
476 assertXpathValuesEqual("//jvm[4]/@latest", "//jvm[4]/@current",
477 myJavaFlavours);
478 assertXpathValuesNotEqual("//jvm[2]/@current",
479 "//jvm[3]/@current", myJavaFlavours);
480 }</pre></div></div><br class="example-break">
481
482 <p>XPaths are especially useful where a document is made up
483 largely of known, unchanging content with only a small amount of
484 changing content created by the system. One of the main areas
485 where constant "boilerplate" markup is combined with system
486 generated markup is of course in web applications. The power of
487 XPath expressions can make testing web page output quite
488 trivial, and XMLUnit supplies a means of converting even very
489 badly formed HTML into XML to aid this approach to
490 testing.</p>
491
492 <p>The <code class="literal">HTMLDocumentBuilder</code> class uses the
493 Swing HTML parser to convert marked-up content to Sax
494 events. The <code class="literal">TolerantSaxDocumentBuilder</code> class
495 handles the Sax events to build up a DOM document in a tolerant
496 fashion i.e. without mandating that opened elements are
497 closed. (In a purely XML world this class would have no purpose
498 as there are plenty of Sax event handlers that can build DOM
499 documents from well formed content). The test below illustrates
500 how the use of these classes:</p>
501
502 <div class="example"><a name="idp42487344"></a><p class="title"><b>Example 13. Working with non well-formed HTML</b></p><div class="example-contents">
503 <pre class="programlisting">
504 public void testXpathsInHTML() throws Exception {
505 String someBadlyFormedHTML = "&lt;html&gt;&lt;title&gt;Ugh&lt;/title&gt;"
506 + "&lt;body&gt;&lt;h1&gt;Heading&lt;ul&gt;"
507 + "&lt;li id='1'&gt;Item One&lt;li id='2'&gt;Item Two";
508 TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder =
509 new TolerantSaxDocumentBuilder(XMLUnit.getTestParser());
510 HTMLDocumentBuilder htmlDocumentBuilder =
511 new HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
512 Document wellFormedDocument =
513 htmlDocumentBuilder.parse(someBadlyFormedHTML);
514 assertXpathEvaluatesTo("Item One", "/html/body//li[@id='1']",
515 wellFormedDocument);
516 }</pre></div></div><br class="example-break">
517
518 <p>One of the key points about using XPaths with HTML content
519 is that extracting values in tests requires the values to be
520 identifiable. (This is just another way of saying that testing
521 HTML is easier when it is written to be testable.) In the
522 previous example id attributes were used to identify the list
523 item values that needed to be testable, however class attributes
524 or span and div tags can also be used to identify specific
525 content for testing.</p>
526
527 </div>
528
529 <div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Testing%20by%20Tree%20Walking"></a>1.9. Testing by Tree Walking</h3></div></div></div>
530
531
532 <p>The DOM specification allows a <code class="literal">Document</code>
533 to optionally implement the <code class="literal">DocumentTraversal</code>
534 interface. This interface allows an application to iterate over
535 the <code class="literal">Node</code>s contained in a
536 <code class="literal">Document</code>, or to "walk the DOM tree". The
537 XMLUnit <code class="literal">NodeTest</code> class and
538 <code class="literal">NodeTester</code> interface make use of
539 <code class="literal">DocumentTraversal</code> to expose individual
540 <code class="literal">Node</code>s in tests: the former handles the
541 mechanics of iteration, and the latter allows custom test
542 strategies to be implemented. A sample test strategy is supplied
543 by the <code class="literal">CountingNodeTester</code> class that counts
544 the nodes presented to it and compares the actual count to an
545 expected count. The test below illustrates its use:</p>
546
547 <div class="example"><a name="idp42499456"></a><p class="title"><b>Example 14. Using <code class="literal">CountingNodeTester</code></b></p><div class="example-contents">
548 <pre class="programlisting">
549 public void testCountingNodeTester() throws Exception {
550 String testXML = "&lt;fibonacci&gt;&lt;val&gt;1&lt;/val&gt;&lt;val&gt;2&lt;/val&gt;&lt;val&gt;3&lt;/val&gt;"
551 + "&lt;val&gt;5&lt;/val&gt;&lt;val&gt;9&lt;/val&gt;&lt;/fibonacci&gt;";
552 CountingNodeTester countingNodeTester = new CountingNodeTester(4);
553 assertNodeTestPasses(testXML, countingNodeTester, Node.TEXT_NODE);
554 }</pre></div></div><br class="example-break">
555
556 <p>This test fails as there are 5 text nodes, and JUnit
557 supplies the following message:</p>
558
559 <pre class="programlisting">
560 Expected node test to pass, but it failed! Counted 5 node(s) but
561 expected 4
562 </pre>
563
564 <p>Note that if your DOM implementation does not support the
565 <code class="literal">DocumentTraversal</code> interface then XMLUnit will
566 throw an <code class="literal">IllegalArgumentException</code> informing
567 you that you cannot use the <code class="literal">NodeTest</code> or
568 <code class="literal">NodeTester</code> classes. Unfortunately even if
569 your DOM implementation does support
570 <code class="literal">DocumentTraversal</code>, attributes are not exposed
571 by iteration: however they can be examined from the
572 <code class="literal">Element</code> node that contains them.</p>
573
574 <p>While the previous test could have been easily performed
575 using XPath, there are times when <code class="literal">Node</code>
576 iteration is more powerful. In general, this is true when there
577 are programmatic relationships between nodes that can be more
578 easily tested iteratively. The following test uses a custom
579 <code class="literal">NodeTester</code> class to illustrate the
580 potential:</p>
581
582 <div class="example"><a name="idp42510224"></a><p class="title"><b>Example 15. Using a Custom <code class="literal">NodeTester</code></b></p><div class="example-contents">
583 <pre class="programlisting">
584 public void testCustomNodeTester() throws Exception {
585 String testXML = "&lt;fibonacci&gt;&lt;val&gt;1&lt;/val&gt;&lt;val&gt;2&lt;/val&gt;&lt;val&gt;3&lt;/val&gt;"
586 + "&lt;val&gt;5&lt;/val&gt;&lt;val&gt;9&lt;/val&gt;&lt;/fibonacci&gt;";
587 NodeTest nodeTest = new NodeTest(testXML);
588 assertNodeTestPasses(nodeTest, new FibonacciNodeTester(),
589 new short[] {Node.TEXT_NODE,
590 Node.ELEMENT_NODE},
591 true);
592 }
593
594 private class FibonacciNodeTester extends AbstractNodeTester {
595 private int nextVal = 1, lastVal = 1, priorVal = 0;
596
597 public void testText(Text text) throws NodeTestException {
598 int val = Integer.parseInt(text.getData());
599 if (nextVal != val) {
600 throw new NodeTestException("Incorrect value", text);
601 }
602 nextVal = val + lastVal;
603 priorVal = lastVal;
604 lastVal = val;
605 }
606
607 public void testElement(Element element) throws NodeTestException {
608 String name = element.getLocalName();
609 if ("fibonacci".equals(name) || "val".equals(name)) {
610 return;
611 }
612 throw new NodeTestException("Unexpected element", element);
613 }
614
615 public void noMoreNodes(NodeTest nodeTest) throws NodeTestException {
616 }
617 }</pre></div></div><br class="example-break">
618
619 <p>The test fails because the XML contains the wrong value
620 for the last number in the sequence:</p>
621
622 <pre class="programlisting">
623 Expected node test to pass, but it failed! Incorrect value [#text: 9]
624 </pre>
625
626 </div>
627 </div>
628
629
630
631
632
633
634
635
636
637
638
639
640
641 <div class="footnotes"><br><hr style="width:100; text-align:left;margin-left: 0"><div id="ftn.more on JUnit" class="footnote"><p><a href="#more%20on%20JUnit" class="para"><sup class="para">[1] </sup></a>For more information on JUnit see <a class="ulink" href="http://www.junit.org" target="_top">http://www.junit.org</a></p></div><div id="ftn.xerces-link" class="footnote"><p><a href="#xerces-link" class="para"><sup class="para">[2] </sup></a><a class="ulink" href="http://xerces.apache.org/" target="_top">http://xerces.apache.org/</a></p></div><div id="ftn.xalan-link" class="footnote"><p><a href="#xalan-link" class="para"><sup class="para">[3] </sup></a><a class="ulink" href="http://xalan.apache.org/" target="_top">http://xalan.apache.org/</a></p></div><div id="ftn.DifferenceConstants" class="footnote"><p><a href="#DifferenceConstants" class="para"><sup class="para">[4] </sup></a>A
642 full set of prototype <code class="literal">Difference</code> instances -
643 one for each type of difference - is defined using final static
644 fields in the <code class="literal">DifferenceConstants</code>
645 class.</p></div><div id="ftn.XpathEngine note" class="footnote"><p><a href="#XpathEngine%20note" class="para"><sup class="para">[5] </sup></a>Each of the
646 <code class="literal">assertXpath...()</code> methods uses an
647 implementation of the <code class="literal">XpathEngine</code> interface
648 to evaluate an XPath expression.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> 2. Using XMLUnit</td></tr></table></div></body></html>