加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
runtest.c 119.05 KB
一键复制 编辑 原始数据 按行查看 历史
陈程 提交于 2022-06-06 21:11 . update libxml2 2.9.13
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681
/*
* runtest.c: C program to run libxml2 regression tests without
* requiring make or Python, and reducing platform dependencies
* to a strict minimum.
*
* To compile on Unixes:
* cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#include "libxml.h"
#include <stdio.h>
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/tree.h>
#include <libxml/uri.h>
#include <libxml/encoding.h>
#ifdef LIBXML_OUTPUT_ENABLED
#ifdef LIBXML_READER_ENABLED
#include <libxml/xmlreader.h>
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
#endif
#ifdef LIBXML_XPATH_ENABLED
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#ifdef LIBXML_XPTR_ENABLED
#include <libxml/xpointer.h>
#endif
#endif
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
#include <libxml/xmlschemastypes.h>
#endif
#ifdef LIBXML_PATTERN_ENABLED
#include <libxml/pattern.h>
#endif
#ifdef LIBXML_C14N_ENABLED
#include <libxml/c14n.h>
#endif
#ifdef LIBXML_HTML_ENABLED
#include <libxml/HTMLparser.h>
#include <libxml/HTMLtree.h>
/*
* pseudo flag for the unification of HTML and XML tests
*/
#define XML_PARSE_HTML 1 << 24
#endif
#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
#include <libxml/globals.h>
#include <libxml/threads.h>
#include <libxml/parser.h>
#include <libxml/catalog.h>
#include <string.h>
#endif
/*
* O_BINARY is just for Windows compatibility - if it isn't defined
* on this system, avoid any compilation error
*/
#ifdef O_BINARY
#define RD_FLAGS O_RDONLY | O_BINARY
#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
#else
#define RD_FLAGS O_RDONLY
#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC
#endif
typedef int (*functest) (const char *filename, const char *result,
const char *error, int options);
typedef struct testDesc testDesc;
typedef testDesc *testDescPtr;
struct testDesc {
const char *desc; /* description of the test */
functest func; /* function implementing the test */
const char *in; /* glob to path for input files */
const char *out; /* output directory */
const char *suffix;/* suffix for output files */
const char *err; /* suffix for error output files */
int options; /* parser options for the test */
};
static int update_results = 0;
static char* temp_directory = NULL;
static int checkTestFile(const char *filename);
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#include <io.h>
typedef struct
{
size_t gl_pathc; /* Count of paths matched so far */
char **gl_pathv; /* List of matched pathnames. */
size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
} glob_t;
#define GLOB_DOOFFS 0
static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
glob_t *pglob) {
glob_t *ret;
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
unsigned int nb_paths = 0;
char directory[500];
int len;
if ((pattern == NULL) || (pglob == NULL)) return(-1);
strncpy(directory, pattern, 499);
for (len = strlen(directory);len >= 0;len--) {
if (directory[len] == '/') {
len++;
directory[len] = 0;
break;
}
}
if (len <= 0)
len = 0;
ret = pglob;
memset(ret, 0, sizeof(glob_t));
hFind = FindFirstFileA(pattern, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
return(0);
nb_paths = 20;
ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
if (ret->gl_pathv == NULL) {
FindClose(hFind);
return(-1);
}
strncpy(directory + len, FindFileData.cFileName, 499 - len);
ret->gl_pathv[ret->gl_pathc] = strdup(directory);
if (ret->gl_pathv[ret->gl_pathc] == NULL)
goto done;
ret->gl_pathc++;
while(FindNextFileA(hFind, &FindFileData)) {
if (FindFileData.cFileName[0] == '.')
continue;
if (ret->gl_pathc + 2 > nb_paths) {
char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
if (tmp == NULL)
break;
ret->gl_pathv = tmp;
nb_paths *= 2;
}
strncpy(directory + len, FindFileData.cFileName, 499 - len);
ret->gl_pathv[ret->gl_pathc] = strdup(directory);
if (ret->gl_pathv[ret->gl_pathc] == NULL)
break;
ret->gl_pathc++;
}
ret->gl_pathv[ret->gl_pathc] = NULL;
done:
FindClose(hFind);
return(0);
}
static void globfree(glob_t *pglob) {
unsigned int i;
if (pglob == NULL)
return;
for (i = 0;i < pglob->gl_pathc;i++) {
if (pglob->gl_pathv[i] != NULL)
free(pglob->gl_pathv[i]);
}
}
#else
#include <glob.h>
#endif
/************************************************************************
* *
* Libxml2 specific routines *
* *
************************************************************************/
static int nb_tests = 0;
static int nb_errors = 0;
static int nb_leaks = 0;
static int extraMemoryFromResolver = 0;
static int
fatalError(void) {
fprintf(stderr, "Exitting tests on fatal error\n");
exit(1);
}
/*
* We need to trap calls to the resolver to not account memory for the catalog
* which is shared to the current running test. We also don't want to have
* network downloads modifying tests.
*/
static xmlParserInputPtr
testExternalEntityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
xmlParserInputPtr ret;
if (checkTestFile(URL)) {
ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
} else {
int memused = xmlMemUsed();
ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
extraMemoryFromResolver += xmlMemUsed() - memused;
}
return(ret);
}
/*
* Trapping the error messages at the generic level to grab the equivalent of
* stderr messages on CLI tools.
*/
static char testErrors[32769];
static int testErrorsSize = 0;
static void XMLCDECL
testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
va_list args;
int res;
if (testErrorsSize >= 32768)
return;
va_start(args, msg);
res = vsnprintf(&testErrors[testErrorsSize],
32768 - testErrorsSize,
msg, args);
va_end(args);
if (testErrorsSize + res >= 32768) {
/* buffer is full */
testErrorsSize = 32768;
testErrors[testErrorsSize] = 0;
} else {
testErrorsSize += res;
}
testErrors[testErrorsSize] = 0;
}
static void XMLCDECL
channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
va_list args;
int res;
if (testErrorsSize >= 32768)
return;
va_start(args, msg);
res = vsnprintf(&testErrors[testErrorsSize],
32768 - testErrorsSize,
msg, args);
va_end(args);
if (testErrorsSize + res >= 32768) {
/* buffer is full */
testErrorsSize = 32768;
testErrors[testErrorsSize] = 0;
} else {
testErrorsSize += res;
}
testErrors[testErrorsSize] = 0;
}
/**
* xmlParserPrintFileContext:
* @input: an xmlParserInputPtr input
*
* Displays current context within the input content for error tracking
*/
static void
xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
xmlGenericErrorFunc chanl, void *data ) {
const xmlChar *cur, *base;
unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
xmlChar content[81]; /* space for 80 chars + line terminator */
xmlChar *ctnt;
if (input == NULL) return;
cur = input->cur;
base = input->base;
/* skip backwards over any end-of-lines */
while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
cur--;
}
n = 0;
/* search backwards for beginning-of-line (to max buff size) */
while ((n++ < (sizeof(content)-1)) && (cur > base) &&
(*(cur) != '\n') && (*(cur) != '\r'))
cur--;
if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
/* calculate the error position in terms of the current position */
col = input->cur - cur;
/* search forward for end-of-line (to max buff size) */
n = 0;
ctnt = content;
/* copy selected text to our buffer */
while ((*cur != 0) && (*(cur) != '\n') &&
(*(cur) != '\r') && (n < sizeof(content)-1)) {
*ctnt++ = *cur++;
n++;
}
*ctnt = 0;
/* print out the selected text */
chanl(data ,"%s\n", content);
/* create blank line with problem pointer */
n = 0;
ctnt = content;
/* (leave buffer space for pointer + line terminator) */
while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
if (*(ctnt) != '\t')
*(ctnt) = ' ';
ctnt++;
}
*ctnt++ = '^';
*ctnt = 0;
chanl(data ,"%s\n", content);
}
static void
testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
char *file = NULL;
int line = 0;
int code = -1;
int domain;
void *data = NULL;
const char *str;
const xmlChar *name = NULL;
xmlNodePtr node;
xmlErrorLevel level;
xmlParserInputPtr input = NULL;
xmlParserInputPtr cur = NULL;
xmlParserCtxtPtr ctxt = NULL;
if (err == NULL)
return;
file = err->file;
line = err->line;
code = err->code;
domain = err->domain;
level = err->level;
node = err->node;
if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
(domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
ctxt = err->ctxt;
}
str = err->message;
if (code == XML_ERR_OK)
return;
if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
name = node->name;
/*
* Maintain the compatibility with the legacy error handling
*/
if (ctxt != NULL) {
input = ctxt->input;
if ((input != NULL) && (input->filename == NULL) &&
(ctxt->inputNr > 1)) {
cur = input;
input = ctxt->inputTab[ctxt->inputNr - 2];
}
if (input != NULL) {
if (input->filename)
channel(data, "%s:%d: ", input->filename, input->line);
else if ((line != 0) && (domain == XML_FROM_PARSER))
channel(data, "Entity: line %d: ", input->line);
}
} else {
if (file != NULL)
channel(data, "%s:%d: ", file, line);
else if ((line != 0) && (domain == XML_FROM_PARSER))
channel(data, "Entity: line %d: ", line);
}
if (name != NULL) {
channel(data, "element %s: ", name);
}
if (code == XML_ERR_OK)
return;
switch (domain) {
case XML_FROM_PARSER:
channel(data, "parser ");
break;
case XML_FROM_NAMESPACE:
channel(data, "namespace ");
break;
case XML_FROM_DTD:
case XML_FROM_VALID:
channel(data, "validity ");
break;
case XML_FROM_HTML:
channel(data, "HTML parser ");
break;
case XML_FROM_MEMORY:
channel(data, "memory ");
break;
case XML_FROM_OUTPUT:
channel(data, "output ");
break;
case XML_FROM_IO:
channel(data, "I/O ");
break;
case XML_FROM_XINCLUDE:
channel(data, "XInclude ");
break;
case XML_FROM_XPATH:
channel(data, "XPath ");
break;
case XML_FROM_XPOINTER:
channel(data, "parser ");
break;
case XML_FROM_REGEXP:
channel(data, "regexp ");
break;
case XML_FROM_MODULE:
channel(data, "module ");
break;
case XML_FROM_SCHEMASV:
channel(data, "Schemas validity ");
break;
case XML_FROM_SCHEMASP:
channel(data, "Schemas parser ");
break;
case XML_FROM_RELAXNGP:
channel(data, "Relax-NG parser ");
break;
case XML_FROM_RELAXNGV:
channel(data, "Relax-NG validity ");
break;
case XML_FROM_CATALOG:
channel(data, "Catalog ");
break;
case XML_FROM_C14N:
channel(data, "C14N ");
break;
case XML_FROM_XSLT:
channel(data, "XSLT ");
break;
default:
break;
}
if (code == XML_ERR_OK)
return;
switch (level) {
case XML_ERR_NONE:
channel(data, ": ");
break;
case XML_ERR_WARNING:
channel(data, "warning : ");
break;
case XML_ERR_ERROR:
channel(data, "error : ");
break;
case XML_ERR_FATAL:
channel(data, "error : ");
break;
}
if (code == XML_ERR_OK)
return;
if (str != NULL) {
int len;
len = xmlStrlen((const xmlChar *)str);
if ((len > 0) && (str[len - 1] != '\n'))
channel(data, "%s\n", str);
else
channel(data, "%s", str);
} else {
channel(data, "%s\n", "out of memory error");
}
if (code == XML_ERR_OK)
return;
if (ctxt != NULL) {
xmlParserPrintFileContextInternal(input, channel, data);
if (cur != NULL) {
if (cur->filename)
channel(data, "%s:%d: \n", cur->filename, cur->line);
else if ((line != 0) && (domain == XML_FROM_PARSER))
channel(data, "Entity: line %d: \n", cur->line);
xmlParserPrintFileContextInternal(cur, channel, data);
}
}
if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
(err->int1 < 100) &&
(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
xmlChar buf[150];
int i;
channel(data, "%s\n", err->str1);
for (i=0;i < err->int1;i++)
buf[i] = ' ';
buf[i++] = '^';
buf[i] = 0;
channel(data, "%s\n", buf);
}
}
static void
initializeLibxml2(void) {
xmlGetWarningsDefaultValue = 0;
xmlPedanticParserDefault(0);
xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
xmlInitParser();
xmlSetExternalEntityLoader(testExternalEntityLoader);
xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
#ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaInitTypes();
xmlRelaxNGInitTypes();
#endif
}
/************************************************************************
* *
* File name and path utilities *
* *
************************************************************************/
static const char *baseFilename(const char *filename) {
const char *cur;
if (filename == NULL)
return(NULL);
cur = &filename[strlen(filename)];
while ((cur > filename) && (*cur != '/'))
cur--;
if (*cur == '/')
return(cur + 1);
return(cur);
}
static char *resultFilename(const char *filename, const char *out,
const char *suffix) {
const char *base;
char res[500];
char suffixbuff[500];
/*************
if ((filename[0] == 't') && (filename[1] == 'e') &&
(filename[2] == 's') && (filename[3] == 't') &&
(filename[4] == '/'))
filename = &filename[5];
*************/
base = baseFilename(filename);
if (suffix == NULL)
suffix = ".tmp";
if (out == NULL)
out = "";
strncpy(suffixbuff,suffix,499);
#ifdef VMS
if(strstr(base,".") && suffixbuff[0]=='.')
suffixbuff[0]='_';
#endif
if (snprintf(res, 499, "%s%s%s", out, base, suffixbuff) >= 499)
res[499] = 0;
return(strdup(res));
}
static int checkTestFile(const char *filename) {
struct stat buf;
if (stat(filename, &buf) == -1)
return(0);
#if defined(_WIN32) && !defined(__CYGWIN__)
if (!(buf.st_mode & _S_IFREG))
return(0);
#else
if (!S_ISREG(buf.st_mode))
return(0);
#endif
return(1);
}
static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) {
int res1, res2;
int fd1, fd2;
char bytes1[4096];
char bytes2[4096];
if (update_results) {
fd1 = open(r1, RD_FLAGS);
if (fd1 < 0)
return(-1);
fd2 = open(r2, WR_FLAGS, 0644);
if (fd2 < 0) {
close(fd1);
return(-1);
}
do {
res1 = read(fd1, bytes1, 4096);
if (res1 <= 0)
break;
res2 = write(fd2, bytes1, res1);
if (res2 <= 0 || res2 != res1)
break;
} while (1);
close(fd2);
close(fd1);
return(res1 != 0);
}
fd1 = open(r1, RD_FLAGS);
if (fd1 < 0)
return(-1);
fd2 = open(r2, RD_FLAGS);
if (fd2 < 0) {
close(fd1);
return(-1);
}
while (1) {
res1 = read(fd1, bytes1, 4096);
res2 = read(fd2, bytes2, 4096);
if ((res1 != res2) || (res1 < 0)) {
close(fd1);
close(fd2);
return(1);
}
if (res1 == 0)
break;
if (memcmp(bytes1, bytes2, res1) != 0) {
close(fd1);
close(fd2);
return(1);
}
}
close(fd1);
close(fd2);
return(0);
}
static int compareFileMem(const char *filename, const char *mem, int size) {
int res;
int fd;
char bytes[4096];
int idx = 0;
struct stat info;
if (update_results) {
fd = open(filename, WR_FLAGS, 0644);
if (fd < 0) {
fprintf(stderr, "failed to open %s for writing", filename);
return(-1);
}
res = write(fd, mem, size);
close(fd);
return(res != size);
}
if (stat(filename, &info) < 0) {
fprintf(stderr, "failed to stat %s\n", filename);
return(-1);
}
if (info.st_size != size) {
fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
filename, (long) info.st_size, size);
return(-1);
}
fd = open(filename, RD_FLAGS);
if (fd < 0) {
fprintf(stderr, "failed to open %s for reading", filename);
return(-1);
}
while (idx < size) {
res = read(fd, bytes, 4096);
if (res <= 0)
break;
if (res + idx > size)
break;
if (memcmp(bytes, &mem[idx], res) != 0) {
int ix;
for (ix=0; ix<res; ix++)
if (bytes[ix] != mem[idx+ix])
break;
fprintf(stderr,"Compare error at position %d\n", idx+ix);
close(fd);
return(1);
}
idx += res;
}
close(fd);
if (idx != size) {
fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
}
return(idx != size);
}
static int loadMem(const char *filename, const char **mem, int *size) {
int fd, res;
struct stat info;
char *base;
int siz = 0;
if (stat(filename, &info) < 0)
return(-1);
base = malloc(info.st_size + 1);
if (base == NULL)
return(-1);
if ((fd = open(filename, RD_FLAGS)) < 0) {
free(base);
return(-1);
}
while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
siz += res;
}
close(fd);
#if !defined(_WIN32)
if (siz != info.st_size) {
free(base);
return(-1);
}
#endif
base[siz] = 0;
*mem = base;
*size = siz;
return(0);
}
static int unloadMem(const char *mem) {
free((char *)mem);
return(0);
}
/************************************************************************
* *
* Tests implementations *
* *
************************************************************************/
/************************************************************************
* *
* Parse to SAX based tests *
* *
************************************************************************/
static FILE *SAXdebug = NULL;
/*
* empty SAX block
*/
static xmlSAXHandler emptySAXHandlerStruct = {
NULL, /* internalSubset */
NULL, /* isStandalone */
NULL, /* hasInternalSubset */
NULL, /* hasExternalSubset */
NULL, /* resolveEntity */
NULL, /* getEntity */
NULL, /* entityDecl */
NULL, /* notationDecl */
NULL, /* attributeDecl */
NULL, /* elementDecl */
NULL, /* unparsedEntityDecl */
NULL, /* setDocumentLocator */
NULL, /* startDocument */
NULL, /* endDocument */
NULL, /* startElement */
NULL, /* endElement */
NULL, /* reference */
NULL, /* characters */
NULL, /* ignorableWhitespace */
NULL, /* processingInstruction */
NULL, /* comment */
NULL, /* xmlParserWarning */
NULL, /* xmlParserError */
NULL, /* xmlParserError */
NULL, /* getParameterEntity */
NULL, /* cdataBlock; */
NULL, /* externalSubset; */
1,
NULL,
NULL, /* startElementNs */
NULL, /* endElementNs */
NULL /* xmlStructuredErrorFunc */
};
static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
static int callbacks = 0;
static int quiet = 0;
/**
* isStandaloneDebug:
* @ctxt: An XML parser context
*
* Is this document tagged standalone ?
*
* Returns 1 if true
*/
static int
isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return(0);
fprintf(SAXdebug, "SAX.isStandalone()\n");
return(0);
}
/**
* hasInternalSubsetDebug:
* @ctxt: An XML parser context
*
* Does this document has an internal subset
*
* Returns 1 if true
*/
static int
hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return(0);
fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
return(0);
}
/**
* hasExternalSubsetDebug:
* @ctxt: An XML parser context
*
* Does this document has an external subset
*
* Returns 1 if true
*/
static int
hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return(0);
fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
return(0);
}
/**
* internalSubsetDebug:
* @ctxt: An XML parser context
*
* Does this document has an internal subset
*/
static void
internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
callbacks++;
if (quiet)
return;
if (name == NULL)
name = BAD_CAST "(null)";
fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
if (ExternalID == NULL)
fprintf(SAXdebug, " ,");
else
fprintf(SAXdebug, " %s,", ExternalID);
if (SystemID == NULL)
fprintf(SAXdebug, " )\n");
else
fprintf(SAXdebug, " %s)\n", SystemID);
}
/**
* externalSubsetDebug:
* @ctxt: An XML parser context
*
* Does this document has an external subset
*/
static void
externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
if (ExternalID == NULL)
fprintf(SAXdebug, " ,");
else
fprintf(SAXdebug, " %s,", ExternalID);
if (SystemID == NULL)
fprintf(SAXdebug, " )\n");
else
fprintf(SAXdebug, " %s)\n", SystemID);
}
/**
* resolveEntityDebug:
* @ctxt: An XML parser context
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
*
* Special entity resolver, better left to the parser, it has
* more context than the application layer.
* The default behaviour is to NOT resolve the entities, in that case
* the ENTITY_REF nodes are built in the structure (and the parameter
* values).
*
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
*/
static xmlParserInputPtr
resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
{
callbacks++;
if (quiet)
return(NULL);
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
fprintf(SAXdebug, "SAX.resolveEntity(");
if (publicId != NULL)
fprintf(SAXdebug, "%s", (char *)publicId);
else
fprintf(SAXdebug, " ");
if (systemId != NULL)
fprintf(SAXdebug, ", %s)\n", (char *)systemId);
else
fprintf(SAXdebug, ", )\n");
/*********
if (systemId != NULL) {
return(xmlNewInputFromFile(ctxt, (char *) systemId));
}
*********/
return(NULL);
}
/**
* getEntityDebug:
* @ctxt: An XML parser context
* @name: The entity name
*
* Get an entity by name
*
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
*/
static xmlEntityPtr
getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
{
callbacks++;
if (quiet)
return(NULL);
fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
return(NULL);
}
/**
* getParameterEntityDebug:
* @ctxt: An XML parser context
* @name: The entity name
*
* Get a parameter entity by name
*
* Returns the xmlParserInputPtr
*/
static xmlEntityPtr
getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
{
callbacks++;
if (quiet)
return(NULL);
fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
return(NULL);
}
/**
* entityDeclDebug:
* @ctxt: An XML parser context
* @name: the entity name
* @type: the entity type
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
* @content: the entity value (without processing).
*
* An entity definition has been parsed
*/
static void
entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
{
const xmlChar *nullstr = BAD_CAST "(null)";
/* not all libraries handle printing null pointers nicely */
if (publicId == NULL)
publicId = nullstr;
if (systemId == NULL)
systemId = nullstr;
if (content == NULL)
content = (xmlChar *)nullstr;
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
name, type, publicId, systemId, content);
}
/**
* attributeDeclDebug:
* @ctxt: An XML parser context
* @name: the attribute name
* @type: the attribute type
*
* An attribute definition has been parsed
*/
static void
attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
const xmlChar * name, int type, int def,
const xmlChar * defaultValue, xmlEnumerationPtr tree)
{
callbacks++;
if (quiet)
return;
if (defaultValue == NULL)
fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
elem, name, type, def);
else
fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
elem, name, type, def, defaultValue);
xmlFreeEnumeration(tree);
}
/**
* elementDeclDebug:
* @ctxt: An XML parser context
* @name: the element name
* @type: the element type
* @content: the element value (without processing).
*
* An element definition has been parsed
*/
static void
elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
xmlElementContentPtr content ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
name, type);
}
/**
* notationDeclDebug:
* @ctxt: An XML parser context
* @name: The name of the notation
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
*
* What to do when a notation declaration has been parsed.
*/
static void
notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
(char *) name, (char *) publicId, (char *) systemId);
}
/**
* unparsedEntityDeclDebug:
* @ctxt: An XML parser context
* @name: The name of the entity
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
* @notationName: the name of the notation
*
* What to do when an unparsed entity declaration is parsed
*/
static void
unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId,
const xmlChar *notationName)
{
const xmlChar *nullstr = BAD_CAST "(null)";
if (publicId == NULL)
publicId = nullstr;
if (systemId == NULL)
systemId = nullstr;
if (notationName == NULL)
notationName = nullstr;
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
(char *) name, (char *) publicId, (char *) systemId,
(char *) notationName);
}
/**
* setDocumentLocatorDebug:
* @ctxt: An XML parser context
* @loc: A SAX Locator
*
* Receive the document locator at startup, actually xmlDefaultSAXLocator
* Everything is available on the context, so this is useless in our case.
*/
static void
setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
}
/**
* startDocumentDebug:
* @ctxt: An XML parser context
*
* called when the document start being processed.
*/
static void
startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.startDocument()\n");
}
/**
* endDocumentDebug:
* @ctxt: An XML parser context
*
* called when the document end has been detected.
*/
static void
endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.endDocument()\n");
}
/**
* startElementDebug:
* @ctxt: An XML parser context
* @name: The element name
*
* called when an opening tag has been processed.
*/
static void
startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
{
int i;
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
if (atts != NULL) {
for (i = 0;(atts[i] != NULL);i++) {
fprintf(SAXdebug, ", %s='", atts[i++]);
if (atts[i] != NULL)
fprintf(SAXdebug, "%s'", atts[i]);
}
}
fprintf(SAXdebug, ")\n");
}
/**
* endElementDebug:
* @ctxt: An XML parser context
* @name: The element name
*
* called when the end of an element has been detected.
*/
static void
endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
}
/**
* charactersDebug:
* @ctxt: An XML parser context
* @ch: a xmlChar string
* @len: the number of xmlChar
*
* receiving some chars from the parser.
* Question: how much at a time ???
*/
static void
charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
{
char output[40];
int i;
callbacks++;
if (quiet)
return;
for (i = 0;(i<len) && (i < 30);i++)
output[i] = (char) ch[i];
output[i] = 0;
fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
}
/**
* referenceDebug:
* @ctxt: An XML parser context
* @name: The entity name
*
* called when an entity reference is detected.
*/
static void
referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.reference(%s)\n", name);
}
/**
* ignorableWhitespaceDebug:
* @ctxt: An XML parser context
* @ch: a xmlChar string
* @start: the first char in the string
* @len: the number of xmlChar
*
* receiving some ignorable whitespaces from the parser.
* Question: how much at a time ???
*/
static void
ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
{
char output[40];
int i;
callbacks++;
if (quiet)
return;
for (i = 0;(i<len) && (i < 30);i++)
output[i] = (char) ch[i];
output[i] = 0;
fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
}
/**
* processingInstructionDebug:
* @ctxt: An XML parser context
* @target: the target name
* @data: the PI data's
* @len: the number of xmlChar
*
* A processing instruction has been parsed.
*/
static void
processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
const xmlChar *data)
{
callbacks++;
if (quiet)
return;
if (data != NULL)
fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
(char *) target, (char *) data);
else
fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
(char *) target);
}
/**
* cdataBlockDebug:
* @ctx: the user data (XML parser context)
* @value: The pcdata content
* @len: the block length
*
* called when a pcdata block has been parsed
*/
static void
cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
(char *) value, len);
}
/**
* commentDebug:
* @ctxt: An XML parser context
* @value: the comment content
*
* A comment has been parsed.
*/
static void
commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.comment(%s)\n", value);
}
/**
* warningDebug:
* @ctxt: An XML parser context
* @msg: the message to display/transmit
* @...: extra parameters for the message display
*
* Display and format a warning messages, gives file, line, position and
* extra parameters.
*/
static void XMLCDECL
warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
{
va_list args;
callbacks++;
if (quiet)
return;
va_start(args, msg);
fprintf(SAXdebug, "SAX.warning: ");
vfprintf(SAXdebug, msg, args);
va_end(args);
}
/**
* errorDebug:
* @ctxt: An XML parser context
* @msg: the message to display/transmit
* @...: extra parameters for the message display
*
* Display and format a error messages, gives file, line, position and
* extra parameters.
*/
static void XMLCDECL
errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
{
va_list args;
callbacks++;
if (quiet)
return;
va_start(args, msg);
fprintf(SAXdebug, "SAX.error: ");
vfprintf(SAXdebug, msg, args);
va_end(args);
}
/**
* fatalErrorDebug:
* @ctxt: An XML parser context
* @msg: the message to display/transmit
* @...: extra parameters for the message display
*
* Display and format a fatalError messages, gives file, line, position and
* extra parameters.
*/
static void XMLCDECL
fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
{
va_list args;
callbacks++;
if (quiet)
return;
va_start(args, msg);
fprintf(SAXdebug, "SAX.fatalError: ");
vfprintf(SAXdebug, msg, args);
va_end(args);
}
static xmlSAXHandler debugSAXHandlerStruct = {
internalSubsetDebug,
isStandaloneDebug,
hasInternalSubsetDebug,
hasExternalSubsetDebug,
resolveEntityDebug,
getEntityDebug,
entityDeclDebug,
notationDeclDebug,
attributeDeclDebug,
elementDeclDebug,
unparsedEntityDeclDebug,
setDocumentLocatorDebug,
startDocumentDebug,
endDocumentDebug,
startElementDebug,
endElementDebug,
referenceDebug,
charactersDebug,
ignorableWhitespaceDebug,
processingInstructionDebug,
commentDebug,
warningDebug,
errorDebug,
fatalErrorDebug,
getParameterEntityDebug,
cdataBlockDebug,
externalSubsetDebug,
1,
NULL,
NULL,
NULL,
NULL
};
static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
/*
* SAX2 specific callbacks
*/
/**
* startElementNsDebug:
* @ctxt: An XML parser context
* @name: The element name
*
* called when an opening tag has been processed.
*/
static void
startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar **attributes)
{
int i;
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
if (prefix == NULL)
fprintf(SAXdebug, ", NULL");
else
fprintf(SAXdebug, ", %s", (char *) prefix);
if (URI == NULL)
fprintf(SAXdebug, ", NULL");
else
fprintf(SAXdebug, ", '%s'", (char *) URI);
fprintf(SAXdebug, ", %d", nb_namespaces);
if (namespaces != NULL) {
for (i = 0;i < nb_namespaces * 2;i++) {
fprintf(SAXdebug, ", xmlns");
if (namespaces[i] != NULL)
fprintf(SAXdebug, ":%s", namespaces[i]);
i++;
fprintf(SAXdebug, "='%s'", namespaces[i]);
}
}
fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
if (attributes != NULL) {
for (i = 0;i < nb_attributes * 5;i += 5) {
if (attributes[i + 1] != NULL)
fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
else
fprintf(SAXdebug, ", %s='", attributes[i]);
fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
(int)(attributes[i + 4] - attributes[i + 3]));
}
}
fprintf(SAXdebug, ")\n");
}
/**
* endElementDebug:
* @ctxt: An XML parser context
* @name: The element name
*
* called when the end of an element has been detected.
*/
static void
endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI)
{
callbacks++;
if (quiet)
return;
fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
if (prefix == NULL)
fprintf(SAXdebug, ", NULL");
else
fprintf(SAXdebug, ", %s", (char *) prefix);
if (URI == NULL)
fprintf(SAXdebug, ", NULL)\n");
else
fprintf(SAXdebug, ", '%s')\n", (char *) URI);
}
static xmlSAXHandler debugSAX2HandlerStruct = {
internalSubsetDebug,
isStandaloneDebug,
hasInternalSubsetDebug,
hasExternalSubsetDebug,
resolveEntityDebug,
getEntityDebug,
entityDeclDebug,
notationDeclDebug,
attributeDeclDebug,
elementDeclDebug,
unparsedEntityDeclDebug,
setDocumentLocatorDebug,
startDocumentDebug,
endDocumentDebug,
NULL,
NULL,
referenceDebug,
charactersDebug,
ignorableWhitespaceDebug,
processingInstructionDebug,
commentDebug,
warningDebug,
errorDebug,
fatalErrorDebug,
getParameterEntityDebug,
cdataBlockDebug,
externalSubsetDebug,
XML_SAX2_MAGIC,
NULL,
startElementNsDebug,
endElementNsDebug,
NULL
};
static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
#ifdef LIBXML_HTML_ENABLED
/**
* htmlstartElementDebug:
* @ctxt: An XML parser context
* @name: The element name
*
* called when an opening tag has been processed.
*/
static void
htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
{
int i;
fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
if (atts != NULL) {
for (i = 0;(atts[i] != NULL);i++) {
fprintf(SAXdebug, ", %s", atts[i++]);
if (atts[i] != NULL) {
unsigned char output[40];
const unsigned char *att = atts[i];
int outlen, attlen;
fprintf(SAXdebug, "='");
while ((attlen = strlen((char*)att)) > 0) {
outlen = sizeof output - 1;
htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
output[outlen] = 0;
fprintf(SAXdebug, "%s", (char *) output);
att += attlen;
}
fprintf(SAXdebug, "'");
}
}
}
fprintf(SAXdebug, ")\n");
}
/**
* htmlcharactersDebug:
* @ctxt: An XML parser context
* @ch: a xmlChar string
* @len: the number of xmlChar
*
* receiving some chars from the parser.
* Question: how much at a time ???
*/
static void
htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
{
unsigned char output[40];
int inlen = len, outlen = 30;
htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
output[outlen] = 0;
fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
}
/**
* htmlcdataDebug:
* @ctxt: An XML parser context
* @ch: a xmlChar string
* @len: the number of xmlChar
*
* receiving some cdata chars from the parser.
* Question: how much at a time ???
*/
static void
htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
{
unsigned char output[40];
int inlen = len, outlen = 30;
htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
output[outlen] = 0;
fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
}
static xmlSAXHandler debugHTMLSAXHandlerStruct = {
internalSubsetDebug,
isStandaloneDebug,
hasInternalSubsetDebug,
hasExternalSubsetDebug,
resolveEntityDebug,
getEntityDebug,
entityDeclDebug,
notationDeclDebug,
attributeDeclDebug,
elementDeclDebug,
unparsedEntityDeclDebug,
setDocumentLocatorDebug,
startDocumentDebug,
endDocumentDebug,
htmlstartElementDebug,
endElementDebug,
referenceDebug,
htmlcharactersDebug,
ignorableWhitespaceDebug,
processingInstructionDebug,
commentDebug,
warningDebug,
errorDebug,
fatalErrorDebug,
getParameterEntityDebug,
htmlcdataDebug,
externalSubsetDebug,
1,
NULL,
NULL,
NULL,
NULL
};
static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
#endif /* LIBXML_HTML_ENABLED */
/**
* saxParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the SAX API and check for errors.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
saxParseTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options) {
int ret;
char *temp;
nb_tests++;
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "out of memory\n");
fatalError();
}
SAXdebug = fopen(temp, "wb");
if (SAXdebug == NULL) {
fprintf(stderr, "Failed to write to %s\n", temp);
free(temp);
return(-1);
}
/* for SAX we really want the callbacks though the context handlers */
xmlSetStructuredErrorFunc(NULL, NULL);
xmlSetGenericErrorFunc(NULL, testErrorHandler);
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
ret = 0;
} else
#endif
{
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
memcpy(ctxt->sax, emptySAXHandler, sizeof(xmlSAXHandler));
xmlCtxtUseOptions(ctxt, options);
xmlParseDocument(ctxt);
ret = ctxt->wellFormed ? 0 : ctxt->errNo;
xmlFreeDoc(ctxt->myDoc);
xmlFreeParserCtxt(ctxt);
}
if (ret == XML_WAR_UNDECLARED_ENTITY) {
fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
ret = 0;
}
if (ret != 0) {
fprintf(stderr, "Failed to parse %s\n", filename);
ret = 1;
goto done;
}
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
ret = 0;
} else
#endif
{
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
if (options & XML_PARSE_SAX1) {
memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
options -= XML_PARSE_SAX1;
} else {
memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
}
xmlCtxtUseOptions(ctxt, options);
xmlParseDocument(ctxt);
ret = ctxt->wellFormed ? 0 : ctxt->errNo;
xmlFreeDoc(ctxt->myDoc);
xmlFreeParserCtxt(ctxt);
}
if (ret == XML_WAR_UNDECLARED_ENTITY) {
fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
ret = 0;
}
fclose(SAXdebug);
if (compareFiles(temp, result)) {
fprintf(stderr, "Got a difference for %s\n", filename);
ret = 1;
}
done:
if (temp != NULL) {
unlink(temp);
free(temp);
}
/* switch back to structured error handling */
xmlSetGenericErrorFunc(NULL, NULL);
xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
return(ret);
}
/************************************************************************
* *
* Parse to tree based tests *
* *
************************************************************************/
/**
* oldParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages: unused
*
* Parse a file using the old xmlParseFile API, then serialize back
* reparse the result and serialize again, then check for deviation
* in serialization.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
oldParseTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
xmlDocPtr doc;
char *temp;
int res = 0;
nb_tests++;
/*
* base of the test, parse with the old API
*/
#ifdef LIBXML_SAX1_ENABLED
doc = xmlParseFile(filename);
#else
doc = xmlReadFile(filename, NULL, 0);
#endif
if (doc == NULL)
return(1);
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "out of memory\n");
fatalError();
}
xmlSaveFile(temp, doc);
if (compareFiles(temp, result)) {
res = 1;
}
xmlFreeDoc(doc);
/*
* Parse the saved result to make sure the round trip is okay
*/
#ifdef LIBXML_SAX1_ENABLED
doc = xmlParseFile(temp);
#else
doc = xmlReadFile(temp, NULL, 0);
#endif
if (doc == NULL)
return(1);
xmlSaveFile(temp, doc);
if (compareFiles(temp, result)) {
res = 1;
}
xmlFreeDoc(doc);
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(res);
}
#ifdef LIBXML_PUSH_ENABLED
/**
* pushParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages: unused
*
* Parse a file using the Push API, then serialize back
* to check for content.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
pushParseTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options) {
xmlParserCtxtPtr ctxt;
xmlDocPtr doc;
const char *base;
int size, res;
int cur = 0;
int chunkSize = 4;
nb_tests++;
/*
* load the document in memory and work from there.
*/
if (loadMem(filename, &base, &size) != 0) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
if (chunkSize > size)
chunkSize = size;
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML)
ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename,
XML_CHAR_ENCODING_NONE);
else
#endif
ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
xmlCtxtUseOptions(ctxt, options);
cur += chunkSize;
chunkSize = 1024;
do {
if (cur + chunkSize >= size) {
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML)
htmlParseChunk(ctxt, base + cur, size - cur, 1);
else
#endif
xmlParseChunk(ctxt, base + cur, size - cur, 1);
break;
} else {
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML)
htmlParseChunk(ctxt, base + cur, chunkSize, 0);
else
#endif
xmlParseChunk(ctxt, base + cur, chunkSize, 0);
cur += chunkSize;
}
} while (cur < size);
doc = ctxt->myDoc;
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML)
res = 1;
else
#endif
res = ctxt->wellFormed;
xmlFreeParserCtxt(ctxt);
free((char *)base);
if (!res) {
xmlFreeDoc(doc);
fprintf(stderr, "Failed to parse %s\n", filename);
return(-1);
}
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML)
htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
else
#endif
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
xmlFreeDoc(doc);
res = compareFileMem(result, base, size);
if ((base == NULL) || (res != 0)) {
if (base != NULL)
xmlFree((char *)base);
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
return(-1);
}
xmlFree((char *)base);
if (err != NULL) {
res = compareFileMem(err, testErrors, testErrorsSize);
if (res != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
return(-1);
}
}
return(0);
}
#endif
/**
* memParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages: unused
*
* Parse a file using the old xmlReadMemory API, then serialize back
* reparse the result and serialize again, then check for deviation
* in serialization.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
memParseTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
xmlDocPtr doc;
const char *base;
int size, res;
nb_tests++;
/*
* load and parse the memory
*/
if (loadMem(filename, &base, &size) != 0) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
doc = xmlReadMemory(base, size, filename, NULL, 0);
unloadMem(base);
if (doc == NULL) {
return(1);
}
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
xmlFreeDoc(doc);
res = compareFileMem(result, base, size);
if ((base == NULL) || (res != 0)) {
if (base != NULL)
xmlFree((char *)base);
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
return(-1);
}
xmlFree((char *)base);
return(0);
}
/**
* noentParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages: unused
*
* Parse a file with entity resolution, then serialize back
* reparse the result and serialize again, then check for deviation
* in serialization.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
noentParseTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options) {
xmlDocPtr doc;
char *temp;
int res = 0;
nb_tests++;
/*
* base of the test, parse with the old API
*/
doc = xmlReadFile(filename, NULL, options);
if (doc == NULL)
return(1);
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
xmlSaveFile(temp, doc);
if (compareFiles(temp, result)) {
res = 1;
}
xmlFreeDoc(doc);
/*
* Parse the saved result to make sure the round trip is okay
*/
doc = xmlReadFile(filename, NULL, options);
if (doc == NULL)
return(1);
xmlSaveFile(temp, doc);
if (compareFiles(temp, result)) {
res = 1;
}
xmlFreeDoc(doc);
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(res);
}
/**
* errParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the xmlReadFile API and check for errors.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
errParseTest(const char *filename, const char *result, const char *err,
int options) {
xmlDocPtr doc;
const char *base = NULL;
int size, res = 0;
nb_tests++;
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
doc = htmlReadFile(filename, NULL, options);
} else
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
if (options & XML_PARSE_XINCLUDE) {
doc = xmlReadFile(filename, NULL, options);
xmlXIncludeProcessFlags(doc, options);
} else
#endif
{
xmlGetWarningsDefaultValue = 1;
doc = xmlReadFile(filename, NULL, options);
}
xmlGetWarningsDefaultValue = 0;
if (result) {
if (doc == NULL) {
base = "";
size = 0;
} else {
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
} else
#endif
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
}
res = compareFileMem(result, base, size);
}
if (doc != NULL) {
if (base != NULL)
xmlFree((char *)base);
xmlFreeDoc(doc);
}
if (res != 0) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
return(-1);
}
if (err != NULL) {
res = compareFileMem(err, testErrors, testErrorsSize);
if (res != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
return(-1);
}
} else if (options & XML_PARSE_DTDVALID) {
if (testErrorsSize != 0)
fprintf(stderr, "Validation for %s failed\n", filename);
}
return(0);
}
/**
* fdParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the xmlReadFd API and check for errors.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
fdParseTest(const char *filename, const char *result, const char *err,
int options) {
xmlDocPtr doc;
const char *base = NULL;
int size, res = 0;
nb_tests++;
int fd = open(filename, RD_FLAGS);
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
doc = htmlReadFd(fd, filename, NULL, options);
} else
#endif
{
xmlGetWarningsDefaultValue = 1;
doc = xmlReadFd(fd, filename, NULL, options);
}
close(fd);
xmlGetWarningsDefaultValue = 0;
if (result) {
if (doc == NULL) {
base = "";
size = 0;
} else {
#ifdef LIBXML_HTML_ENABLED
if (options & XML_PARSE_HTML) {
htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
} else
#endif
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
}
res = compareFileMem(result, base, size);
}
if (doc != NULL) {
if (base != NULL)
xmlFree((char *)base);
xmlFreeDoc(doc);
}
if (res != 0) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
return(-1);
}
if (err != NULL) {
res = compareFileMem(err, testErrors, testErrorsSize);
if (res != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
return(-1);
}
} else if (options & XML_PARSE_DTDVALID) {
if (testErrorsSize != 0)
fprintf(stderr, "Validation for %s failed\n", filename);
}
return(0);
}
#ifdef LIBXML_READER_ENABLED
/************************************************************************
* *
* Reader based tests *
* *
************************************************************************/
static void processNode(FILE *out, xmlTextReaderPtr reader) {
const xmlChar *name, *value;
int type, empty;
type = xmlTextReaderNodeType(reader);
empty = xmlTextReaderIsEmptyElement(reader);
name = xmlTextReaderConstName(reader);
if (name == NULL)
name = BAD_CAST "--";
value = xmlTextReaderConstValue(reader);
fprintf(out, "%d %d %s %d %d",
xmlTextReaderDepth(reader),
type,
name,
empty,
xmlTextReaderHasValue(reader));
if (value == NULL)
fprintf(out, "\n");
else {
fprintf(out, " %s\n", value);
}
}
static int
streamProcessTest(const char *filename, const char *result, const char *err,
xmlTextReaderPtr reader, const char *rng,
int options ATTRIBUTE_UNUSED) {
int ret;
char *temp = NULL;
FILE *t = NULL;
if (reader == NULL)
return(-1);
nb_tests++;
if (result != NULL) {
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
t = fopen(temp, "wb");
if (t == NULL) {
fprintf(stderr, "Can't open temp file %s\n", temp);
free(temp);
return(-1);
}
}
#ifdef LIBXML_SCHEMAS_ENABLED
if (rng != NULL) {
ret = xmlTextReaderRelaxNGValidate(reader, rng);
if (ret < 0) {
testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
rng);
fclose(t);
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(0);
}
}
#endif
xmlGetWarningsDefaultValue = 1;
ret = xmlTextReaderRead(reader);
while (ret == 1) {
if ((t != NULL) && (rng == NULL))
processNode(t, reader);
ret = xmlTextReaderRead(reader);
}
if (ret != 0) {
testErrorHandler(NULL, "%s : failed to parse\n", filename);
}
if (rng != NULL) {
if (xmlTextReaderIsValid(reader) != 1) {
testErrorHandler(NULL, "%s fails to validate\n", filename);
} else {
testErrorHandler(NULL, "%s validates\n", filename);
}
}
xmlGetWarningsDefaultValue = 0;
if (t != NULL) {
fclose(t);
ret = compareFiles(temp, result);
if (temp != NULL) {
unlink(temp);
free(temp);
}
if (ret) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
return(-1);
}
}
if (err != NULL) {
ret = compareFileMem(err, testErrors, testErrorsSize);
if (ret != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
printf("%s", testErrors);
return(-1);
}
}
return(0);
}
/**
* streamParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the reader API and check for errors.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
streamParseTest(const char *filename, const char *result, const char *err,
int options) {
xmlTextReaderPtr reader;
int ret;
reader = xmlReaderForFile(filename, NULL, options);
ret = streamProcessTest(filename, result, err, reader, NULL, options);
xmlFreeTextReader(reader);
return(ret);
}
/**
* walkerParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the walker, i.e. a reader built from a atree.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
walkerParseTest(const char *filename, const char *result, const char *err,
int options) {
xmlDocPtr doc;
xmlTextReaderPtr reader;
int ret;
doc = xmlReadFile(filename, NULL, options);
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", filename);
return(-1);
}
reader = xmlReaderWalker(doc);
ret = streamProcessTest(filename, result, err, reader, NULL, options);
xmlFreeTextReader(reader);
xmlFreeDoc(doc);
return(ret);
}
/**
* streamMemParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file using the reader API from memory and check for errors.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
streamMemParseTest(const char *filename, const char *result, const char *err,
int options) {
xmlTextReaderPtr reader;
int ret;
const char *base;
int size;
/*
* load and parse the memory
*/
if (loadMem(filename, &base, &size) != 0) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
reader = xmlReaderForMemory(base, size, filename, NULL, options);
ret = streamProcessTest(filename, result, err, reader, NULL, options);
free((char *)base);
xmlFreeTextReader(reader);
return(ret);
}
#endif
#ifdef LIBXML_XPATH_ENABLED
#ifdef LIBXML_DEBUG_ENABLED
/************************************************************************
* *
* XPath and XPointer based tests *
* *
************************************************************************/
static FILE *xpathOutput;
static xmlDocPtr xpathDocument;
static void
ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
const char *msg ATTRIBUTE_UNUSED, ...) {
}
static void
testXPath(const char *str, int xptr, int expr) {
xmlGenericErrorFunc handler = ignoreGenericError;
xmlXPathObjectPtr res;
xmlXPathContextPtr ctxt;
/* Don't print generic errors to stderr. */
initGenericErrorDefaultFunc(&handler);
nb_tests++;
#if defined(LIBXML_XPTR_ENABLED)
if (xptr) {
ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
res = xmlXPtrEval(BAD_CAST str, ctxt);
} else {
#endif
ctxt = xmlXPathNewContext(xpathDocument);
ctxt->node = xmlDocGetRootElement(xpathDocument);
if (expr)
res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
else {
/* res = xmlXPathEval(BAD_CAST str, ctxt); */
xmlXPathCompExprPtr comp;
comp = xmlXPathCompile(BAD_CAST str);
if (comp != NULL) {
res = xmlXPathCompiledEval(comp, ctxt);
xmlXPathFreeCompExpr(comp);
} else
res = NULL;
}
#if defined(LIBXML_XPTR_ENABLED)
}
#endif
xmlXPathDebugDumpObject(xpathOutput, res, 0);
xmlXPathFreeObject(res);
xmlXPathFreeContext(ctxt);
/* Reset generic error handler. */
initGenericErrorDefaultFunc(NULL);
}
/**
* xpathExprTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing XPath standalone expressions and evaluate them
*
* Returns 0 in case of success, an error code otherwise
*/
static int
xpathCommonTest(const char *filename, const char *result,
int xptr, int expr) {
FILE *input;
char expression[5000];
int len, ret = 0;
char *temp;
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
xpathOutput = fopen(temp, "wb");
if (xpathOutput == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
free(temp);
return(-1);
}
input = fopen(filename, "rb");
if (input == NULL) {
xmlGenericError(xmlGenericErrorContext,
"Cannot open %s for reading\n", filename);
free(temp);
return(-1);
}
while (fgets(expression, 4500, input) != NULL) {
len = strlen(expression);
len--;
while ((len >= 0) &&
((expression[len] == '\n') || (expression[len] == '\t') ||
(expression[len] == '\r') || (expression[len] == ' '))) len--;
expression[len + 1] = 0;
if (len >= 0) {
fprintf(xpathOutput,
"\n========================\nExpression: %s\n",
expression) ;
testXPath(expression, xptr, expr);
}
}
fclose(input);
fclose(xpathOutput);
if (result != NULL) {
ret = compareFiles(temp, result);
if (ret) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
}
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(ret);
}
/**
* xpathExprTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing XPath standalone expressions and evaluate them
*
* Returns 0 in case of success, an error code otherwise
*/
static int
xpathExprTest(const char *filename, const char *result,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(xpathCommonTest(filename, result, 0, 1));
}
/**
* xpathDocTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing XPath expressions and evaluate them against
* a set of corresponding documents.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
xpathDocTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options) {
char pattern[500];
char result[500];
glob_t globbuf;
size_t i;
int ret = 0, res;
xpathDocument = xmlReadFile(filename, NULL,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
if (xpathDocument == NULL) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
res = snprintf(pattern, 499, "./test/XPath/tests/%s*",
baseFilename(filename));
if (res >= 499)
pattern[499] = 0;
globbuf.gl_offs = 0;
glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
res = snprintf(result, 499, "result/XPath/tests/%s",
baseFilename(globbuf.gl_pathv[i]));
if (res >= 499)
result[499] = 0;
res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
if (res != 0)
ret = res;
}
globfree(&globbuf);
xmlFreeDoc(xpathDocument);
return(ret);
}
#ifdef LIBXML_XPTR_ENABLED
/**
* xptrDocTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing XPath expressions and evaluate them against
* a set of corresponding documents.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
xptrDocTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options) {
char pattern[500];
char result[500];
glob_t globbuf;
size_t i;
int ret = 0, res;
xpathDocument = xmlReadFile(filename, NULL,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
if (xpathDocument == NULL) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
res = snprintf(pattern, 499, "./test/XPath/xptr/%s*",
baseFilename(filename));
if (res >= 499)
pattern[499] = 0;
globbuf.gl_offs = 0;
glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
res = snprintf(result, 499, "result/XPath/xptr/%s",
baseFilename(globbuf.gl_pathv[i]));
if (res >= 499)
result[499] = 0;
res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
if (res != 0)
ret = res;
}
globfree(&globbuf);
xmlFreeDoc(xpathDocument);
return(ret);
}
#endif /* LIBXML_XPTR_ENABLED */
/**
* xmlidDocTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing xml:id and check for errors and verify
* that XPath queries will work on them as expected.
*
* Returns 0 in case of success, an error code otherwise
*/
static int
xmlidDocTest(const char *filename,
const char *result,
const char *err,
int options) {
int res = 0;
int ret = 0;
char *temp;
xpathDocument = xmlReadFile(filename, NULL,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
if (xpathDocument == NULL) {
fprintf(stderr, "Failed to load %s\n", filename);
return(-1);
}
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
xpathOutput = fopen(temp, "wb");
if (xpathOutput == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
xmlFreeDoc(xpathDocument);
free(temp);
return(-1);
}
testXPath("id('bar')", 0, 0);
fclose(xpathOutput);
if (result != NULL) {
ret = compareFiles(temp, result);
if (ret) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
res = 1;
}
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
xmlFreeDoc(xpathDocument);
if (err != NULL) {
ret = compareFileMem(err, testErrors, testErrorsSize);
if (ret != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
res = 1;
}
}
return(res);
}
#endif /* LIBXML_DEBUG_ENABLED */
#endif /* XPATH */
/************************************************************************
* *
* URI based tests *
* *
************************************************************************/
static void
handleURI(const char *str, const char *base, FILE *o) {
int ret;
xmlURIPtr uri;
xmlChar *res = NULL;
uri = xmlCreateURI();
if (base == NULL) {
ret = xmlParseURIReference(uri, str);
if (ret != 0)
fprintf(o, "%s : error %d\n", str, ret);
else {
xmlNormalizeURIPath(uri->path);
xmlPrintURI(o, uri);
fprintf(o, "\n");
}
} else {
res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
if (res != NULL) {
fprintf(o, "%s\n", (char *) res);
}
else
fprintf(o, "::ERROR::\n");
}
if (res != NULL)
xmlFree(res);
xmlFreeURI(uri);
}
/**
* uriCommonTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing URI and check for errors
*
* Returns 0 in case of success, an error code otherwise
*/
static int
uriCommonTest(const char *filename,
const char *result,
const char *err,
const char *base) {
char *temp;
FILE *o, *f;
char str[1024];
int res = 0, i, ret;
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
o = fopen(temp, "wb");
if (o == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
free(temp);
return(-1);
}
f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "failed to open input file %s\n", filename);
fclose(o);
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(-1);
}
while (1) {
/*
* read one line in string buffer.
*/
if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
break;
/*
* remove the ending spaces
*/
i = strlen(str);
while ((i > 0) &&
((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
(str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
i--;
str[i] = 0;
}
nb_tests++;
handleURI(str, base, o);
}
fclose(f);
fclose(o);
if (result != NULL) {
ret = compareFiles(temp, result);
if (ret) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
res = 1;
}
}
if (err != NULL) {
ret = compareFileMem(err, testErrors, testErrorsSize);
if (ret != 0) {
fprintf(stderr, "Error for %s failed\n", filename);
res = 1;
}
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(res);
}
/**
* uriParseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing URI and check for errors
*
* Returns 0 in case of success, an error code otherwise
*/
static int
uriParseTest(const char *filename,
const char *result,
const char *err,
int options ATTRIBUTE_UNUSED) {
return(uriCommonTest(filename, result, err, NULL));
}
/**
* uriBaseTest:
* @filename: the file to parse
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing URI, compose them against a fixed base and
* check for errors
*
* Returns 0 in case of success, an error code otherwise
*/
static int
uriBaseTest(const char *filename,
const char *result,
const char *err,
int options ATTRIBUTE_UNUSED) {
return(uriCommonTest(filename, result, err,
"http://foo.com/path/to/index.html?orig#help"));
}
static int urip_success = 1;
static int urip_current = 0;
static const char *urip_testURLs[] = {
"urip://example.com/a b.html",
"urip://example.com/a%20b.html",
"file:///path/to/a b.html",
"file:///path/to/a%20b.html",
"/path/to/a b.html",
"/path/to/a%20b.html",
"urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
"urip://example.com/test?a=1&b=2%263&c=4#foo",
NULL
};
static const char *urip_rcvsURLs[] = {
/* it is an URI the strings must be escaped */
"urip://example.com/a%20b.html",
/* check that % escaping is not broken */
"urip://example.com/a%20b.html",
/* it's an URI path the strings must be escaped */
"file:///path/to/a%20b.html",
/* check that % escaping is not broken */
"file:///path/to/a%20b.html",
/* this is not an URI, this is a path, so this should not be escaped */
"/path/to/a b.html",
/* check that paths with % are not broken */
"/path/to/a%20b.html",
/* out of context the encoding can't be guessed byte by byte conversion */
"urip://example.com/r%E9sum%E9.html",
/* verify we don't destroy URIs especially the query part */
"urip://example.com/test?a=1&b=2%263&c=4#foo",
NULL
};
static const char *urip_res = "<list/>";
static const char *urip_cur = NULL;
static int urip_rlen;
/**
* uripMatch:
* @URI: an URI to test
*
* Check for an urip: query
*
* Returns 1 if yes and 0 if another Input module should be used
*/
static int
uripMatch(const char * URI) {
if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
return(0);
/* Verify we received the escaped URL */
if (strcmp(urip_rcvsURLs[urip_current], URI))
urip_success = 0;
return(1);
}
/**
* uripOpen:
* @URI: an URI to test
*
* Return a pointer to the urip: query handler, in this example simply
* the urip_current pointer...
*
* Returns an Input context or NULL in case or error
*/
static void *
uripOpen(const char * URI) {
if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
return(NULL);
/* Verify we received the escaped URL */
if (strcmp(urip_rcvsURLs[urip_current], URI))
urip_success = 0;
urip_cur = urip_res;
urip_rlen = strlen(urip_res);
return((void *) urip_cur);
}
/**
* uripClose:
* @context: the read context
*
* Close the urip: query handler
*
* Returns 0 or -1 in case of error
*/
static int
uripClose(void * context) {
if (context == NULL) return(-1);
urip_cur = NULL;
urip_rlen = 0;
return(0);
}
/**
* uripRead:
* @context: the read context
* @buffer: where to store data
* @len: number of bytes to read
*
* Implement an urip: query read.
*
* Returns the number of bytes read or -1 in case of error
*/
static int
uripRead(void * context, char * buffer, int len) {
const char *ptr = (const char *) context;
if ((context == NULL) || (buffer == NULL) || (len < 0))
return(-1);
if (len > urip_rlen) len = urip_rlen;
memcpy(buffer, ptr, len);
urip_rlen -= len;
return(len);
}
static int
urip_checkURL(const char *URL) {
xmlDocPtr doc;
doc = xmlReadFile(URL, NULL, 0);
if (doc == NULL)
return(-1);
xmlFreeDoc(doc);
return(1);
}
/**
* uriPathTest:
* @filename: ignored
* @result: ignored
* @err: ignored
*
* Run a set of tests to check how Path and URI are handled before
* being passed to the I/O layer
*
* Returns 0 in case of success, an error code otherwise
*/
static int
uriPathTest(const char *filename ATTRIBUTE_UNUSED,
const char *result ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
int parsed;
int failures = 0;
/*
* register the new I/O handlers
*/
if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
{
fprintf(stderr, "failed to register HTTP handler\n");
return(-1);
}
for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
urip_success = 1;
parsed = urip_checkURL(urip_testURLs[urip_current]);
if (urip_success != 1) {
fprintf(stderr, "failed the URL passing test for %s",
urip_testURLs[urip_current]);
failures++;
} else if (parsed != 1) {
fprintf(stderr, "failed the parsing test for %s",
urip_testURLs[urip_current]);
failures++;
}
nb_tests++;
}
xmlPopInputCallbacks();
return(failures);
}
#ifdef LIBXML_SCHEMAS_ENABLED
/************************************************************************
* *
* Schemas tests *
* *
************************************************************************/
static int
schemasOneTest(const char *sch,
const char *filename,
const char *result,
const char *err,
int options,
xmlSchemaPtr schemas) {
xmlDocPtr doc;
xmlSchemaValidCtxtPtr ctxt;
int ret = 0;
int validResult = 0;
char *temp;
FILE *schemasOutput;
doc = xmlReadFile(filename, NULL, options);
if (doc == NULL) {
fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
return(-1);
}
temp = resultFilename(result, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
schemasOutput = fopen(temp, "wb");
if (schemasOutput == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
xmlFreeDoc(doc);
free(temp);
return(-1);
}
ctxt = xmlSchemaNewValidCtxt(schemas);
xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
validResult = xmlSchemaValidateDoc(ctxt, doc);
if (validResult == 0) {
fprintf(schemasOutput, "%s validates\n", filename);
} else if (validResult > 0) {
fprintf(schemasOutput, "%s fails to validate\n", filename);
} else {
fprintf(schemasOutput, "%s validation generated an internal error\n",
filename);
}
fclose(schemasOutput);
if (result) {
if (compareFiles(temp, result)) {
fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
ret = 1;
}
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
if ((validResult != 0) && (err != NULL)) {
if (compareFileMem(err, testErrors, testErrorsSize)) {
fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
ret = 1;
}
}
xmlSchemaFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
return(ret);
}
/**
* schemasTest:
* @filename: the schemas file
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a file containing URI, compose them against a fixed base and
* check for errors
*
* Returns 0 in case of success, an error code otherwise
*/
static int
schemasTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *errr ATTRIBUTE_UNUSED,
int options) {
const char *base = baseFilename(filename);
const char *base2;
const char *instance;
xmlSchemaParserCtxtPtr ctxt;
xmlSchemaPtr schemas;
int res = 0, len, ret;
char pattern[500];
char prefix[500];
char result[500];
char err[500];
glob_t globbuf;
size_t i;
char count = 0;
/* first compile the schemas if possible */
ctxt = xmlSchemaNewParserCtxt(filename);
xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
schemas = xmlSchemaParse(ctxt);
xmlSchemaFreeParserCtxt(ctxt);
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen(base);
if ((len > 499) || (len < 5)) {
xmlSchemaFree(schemas);
return(-1);
}
len -= 4; /* remove trailing .xsd */
if (base[len - 2] == '_') {
len -= 2; /* remove subtest number */
}
if (base[len - 2] == '_') {
len -= 2; /* remove subtest number */
}
memcpy(prefix, base, len);
prefix[len] = 0;
if (snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix) >= 499)
pattern[499] = 0;
if (base[len] == '_') {
len += 2;
memcpy(prefix, base, len);
prefix[len] = 0;
}
globbuf.gl_offs = 0;
glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
testErrorsSize = 0;
testErrors[0] = 0;
instance = globbuf.gl_pathv[i];
base2 = baseFilename(instance);
len = strlen(base2);
if ((len > 6) && (base2[len - 6] == '_')) {
count = base2[len - 5];
ret = snprintf(result, 499, "result/schemas/%s_%c",
prefix, count);
if (ret >= 499)
result[499] = 0;
ret = snprintf(err, 499, "result/schemas/%s_%c.err",
prefix, count);
if (ret >= 499)
err[499] = 0;
} else {
fprintf(stderr, "don't know how to process %s\n", instance);
continue;
}
if (schemas == NULL) {
} else {
nb_tests++;
ret = schemasOneTest(filename, instance, result, err,
options, schemas);
if (ret != 0)
res = ret;
}
}
globfree(&globbuf);
xmlSchemaFree(schemas);
return(res);
}
/************************************************************************
* *
* Schemas tests *
* *
************************************************************************/
static int
rngOneTest(const char *sch,
const char *filename,
const char *result,
const char *err,
int options,
xmlRelaxNGPtr schemas) {
xmlDocPtr doc;
xmlRelaxNGValidCtxtPtr ctxt;
int ret = 0;
char *temp;
FILE *schemasOutput;
doc = xmlReadFile(filename, NULL, options);
if (doc == NULL) {
fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
return(-1);
}
temp = resultFilename(result, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
schemasOutput = fopen(temp, "wb");
if (schemasOutput == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
xmlFreeDoc(doc);
free(temp);
return(-1);
}
ctxt = xmlRelaxNGNewValidCtxt(schemas);
xmlRelaxNGSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
ret = xmlRelaxNGValidateDoc(ctxt, doc);
if (ret == 0) {
testErrorHandler(NULL, "%s validates\n", filename);
} else if (ret > 0) {
testErrorHandler(NULL, "%s fails to validate\n", filename);
} else {
testErrorHandler(NULL, "%s validation generated an internal error\n",
filename);
}
fclose(schemasOutput);
ret = 0;
if (result) {
if (compareFiles(temp, result)) {
fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
ret = 1;
}
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
if (err != NULL) {
if (compareFileMem(err, testErrors, testErrorsSize)) {
fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
ret = 1;
printf("%s", testErrors);
}
}
xmlRelaxNGFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
return(ret);
}
/**
* rngTest:
* @filename: the schemas file
* @result: the file with expected result
* @err: the file with error messages
*
* Parse an RNG schemas and then apply it to the related .xml
*
* Returns 0 in case of success, an error code otherwise
*/
static int
rngTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *errr ATTRIBUTE_UNUSED,
int options) {
const char *base = baseFilename(filename);
const char *base2;
const char *instance;
xmlRelaxNGParserCtxtPtr ctxt;
xmlRelaxNGPtr schemas;
int res = 0, len, ret = 0;
char pattern[500];
char prefix[500];
char result[500];
char err[500];
glob_t globbuf;
size_t i;
char count = 0;
/* first compile the schemas if possible */
ctxt = xmlRelaxNGNewParserCtxt(filename);
xmlRelaxNGSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
schemas = xmlRelaxNGParse(ctxt);
xmlRelaxNGFreeParserCtxt(ctxt);
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen(base);
if ((len > 499) || (len < 5)) {
xmlRelaxNGFree(schemas);
return(-1);
}
len -= 4; /* remove trailing .rng */
memcpy(prefix, base, len);
prefix[len] = 0;
if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
pattern[499] = 0;
globbuf.gl_offs = 0;
glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
testErrorsSize = 0;
testErrors[0] = 0;
instance = globbuf.gl_pathv[i];
base2 = baseFilename(instance);
len = strlen(base2);
if ((len > 6) && (base2[len - 6] == '_')) {
count = base2[len - 5];
res = snprintf(result, 499, "result/relaxng/%s_%c",
prefix, count);
if (res >= 499)
result[499] = 0;
res = snprintf(err, 499, "result/relaxng/%s_%c.err",
prefix, count);
if (res >= 499)
err[499] = 0;
} else {
fprintf(stderr, "don't know how to process %s\n", instance);
continue;
}
if (schemas == NULL) {
} else {
nb_tests++;
res = rngOneTest(filename, instance, result, err,
options, schemas);
if (res != 0)
ret = res;
}
}
globfree(&globbuf);
xmlRelaxNGFree(schemas);
return(ret);
}
#ifdef LIBXML_READER_ENABLED
/**
* rngStreamTest:
* @filename: the schemas file
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a set of files with streaming, applying an RNG schemas
*
* Returns 0 in case of success, an error code otherwise
*/
static int
rngStreamTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *errr ATTRIBUTE_UNUSED,
int options) {
const char *base = baseFilename(filename);
const char *base2;
const char *instance;
int res = 0, len, ret;
char pattern[500];
char prefix[500];
char result[500];
char err[500];
glob_t globbuf;
size_t i;
char count = 0;
xmlTextReaderPtr reader;
int disable_err = 0;
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen(base);
if ((len > 499) || (len < 5)) {
fprintf(stderr, "len(base) == %d !\n", len);
return(-1);
}
len -= 4; /* remove trailing .rng */
memcpy(prefix, base, len);
prefix[len] = 0;
/*
* strictly unifying the error messages is nearly impossible this
* hack is also done in the Makefile
*/
if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
(!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
(!strcmp(prefix, "tutor8_2")))
disable_err = 1;
if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
pattern[499] = 0;
globbuf.gl_offs = 0;
glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
testErrorsSize = 0;
testErrors[0] = 0;
instance = globbuf.gl_pathv[i];
base2 = baseFilename(instance);
len = strlen(base2);
if ((len > 6) && (base2[len - 6] == '_')) {
count = base2[len - 5];
ret = snprintf(result, 499, "result/relaxng/%s_%c",
prefix, count);
if (ret >= 499)
result[499] = 0;
ret = snprintf(err, 499, "result/relaxng/%s_%c.err",
prefix, count);
if (ret >= 499)
err[499] = 0;
} else {
fprintf(stderr, "don't know how to process %s\n", instance);
continue;
}
reader = xmlReaderForFile(instance, NULL, options);
if (reader == NULL) {
fprintf(stderr, "Failed to build reader for %s\n", instance);
}
if (disable_err == 1)
ret = streamProcessTest(instance, result, NULL, reader, filename,
options);
else
ret = streamProcessTest(instance, result, err, reader, filename,
options);
xmlFreeTextReader(reader);
if (ret != 0) {
fprintf(stderr, "instance %s failed\n", instance);
res = ret;
}
}
globfree(&globbuf);
return(res);
}
#endif /* READER */
#endif
#ifdef LIBXML_PATTERN_ENABLED
#ifdef LIBXML_READER_ENABLED
/************************************************************************
* *
* Patterns tests *
* *
************************************************************************/
static void patternNode(FILE *out, xmlTextReaderPtr reader,
const char *pattern, xmlPatternPtr patternc,
xmlStreamCtxtPtr patstream) {
xmlChar *path = NULL;
int match = -1;
int type, empty;
type = xmlTextReaderNodeType(reader);
empty = xmlTextReaderIsEmptyElement(reader);
if (type == XML_READER_TYPE_ELEMENT) {
/* do the check only on element start */
match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
if (match) {
path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
fprintf(out, "Node %s matches pattern %s\n", path, pattern);
}
}
if (patstream != NULL) {
int ret;
if (type == XML_READER_TYPE_ELEMENT) {
ret = xmlStreamPush(patstream,
xmlTextReaderConstLocalName(reader),
xmlTextReaderConstNamespaceUri(reader));
if (ret < 0) {
fprintf(out, "xmlStreamPush() failure\n");
xmlFreeStreamCtxt(patstream);
patstream = NULL;
} else if (ret != match) {
if (path == NULL) {
path = xmlGetNodePath(
xmlTextReaderCurrentNode(reader));
}
fprintf(out,
"xmlPatternMatch and xmlStreamPush disagree\n");
fprintf(out,
" pattern %s node %s\n",
pattern, path);
}
}
if ((type == XML_READER_TYPE_END_ELEMENT) ||
((type == XML_READER_TYPE_ELEMENT) && (empty))) {
ret = xmlStreamPop(patstream);
if (ret < 0) {
fprintf(out, "xmlStreamPop() failure\n");
xmlFreeStreamCtxt(patstream);
patstream = NULL;
}
}
}
if (path != NULL)
xmlFree(path);
}
/**
* patternTest:
* @filename: the schemas file
* @result: the file with expected result
* @err: the file with error messages
*
* Parse a set of files with streaming, applying an RNG schemas
*
* Returns 0 in case of success, an error code otherwise
*/
static int
patternTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options) {
xmlPatternPtr patternc = NULL;
xmlStreamCtxtPtr patstream = NULL;
FILE *o, *f;
char str[1024];
char xml[500];
char result[500];
int len, i;
int ret = 0, res;
char *temp;
xmlTextReaderPtr reader;
xmlDocPtr doc;
len = strlen(filename);
len -= 4;
memcpy(xml, filename, len);
xml[len] = 0;
if (snprintf(result, 499, "result/pattern/%s", baseFilename(xml)) >= 499)
result[499] = 0;
memcpy(xml + len, ".xml", 5);
if (!checkTestFile(xml) && !update_results) {
fprintf(stderr, "Missing xml file %s\n", xml);
return(-1);
}
if (!checkTestFile(result) && !update_results) {
fprintf(stderr, "Missing result file %s\n", result);
return(-1);
}
f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "Failed to open %s\n", filename);
return(-1);
}
temp = resultFilename(filename, temp_directory, ".res");
if (temp == NULL) {
fprintf(stderr, "Out of memory\n");
fatalError();
}
o = fopen(temp, "wb");
if (o == NULL) {
fprintf(stderr, "failed to open output file %s\n", temp);
fclose(f);
free(temp);
return(-1);
}
while (1) {
/*
* read one line in string buffer.
*/
if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
break;
/*
* remove the ending spaces
*/
i = strlen(str);
while ((i > 0) &&
((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
(str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
i--;
str[i] = 0;
}
doc = xmlReadFile(xml, NULL, options);
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", xml);
ret = 1;
} else {
xmlNodePtr root;
const xmlChar *namespaces[22];
int j;
xmlNsPtr ns;
root = xmlDocGetRootElement(doc);
for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
namespaces[j++] = ns->href;
namespaces[j++] = ns->prefix;
}
namespaces[j++] = NULL;
namespaces[j] = NULL;
patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
0, &namespaces[0]);
if (patternc == NULL) {
testErrorHandler(NULL,
"Pattern %s failed to compile\n", str);
xmlFreeDoc(doc);
ret = 1;
continue;
}
patstream = xmlPatternGetStreamCtxt(patternc);
if (patstream != NULL) {
ret = xmlStreamPush(patstream, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "xmlStreamPush() failure\n");
xmlFreeStreamCtxt(patstream);
patstream = NULL;
}
}
nb_tests++;
reader = xmlReaderWalker(doc);
res = xmlTextReaderRead(reader);
while (res == 1) {
patternNode(o, reader, str, patternc, patstream);
res = xmlTextReaderRead(reader);
}
if (res != 0) {
fprintf(o, "%s : failed to parse\n", filename);
}
xmlFreeTextReader(reader);
xmlFreeDoc(doc);
xmlFreeStreamCtxt(patstream);
patstream = NULL;
xmlFreePattern(patternc);
}
}
fclose(f);
fclose(o);
ret = compareFiles(temp, result);
if (ret) {
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
ret = 1;
}
if (temp != NULL) {
unlink(temp);
free(temp);
}
return(ret);
}
#endif /* READER */
#endif /* PATTERN */
#ifdef LIBXML_C14N_ENABLED
/************************************************************************
* *
* Canonicalization tests *
* *
************************************************************************/
static xmlXPathObjectPtr
load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
xmlXPathObjectPtr xpath;
xmlDocPtr doc;
xmlChar *expr;
xmlXPathContextPtr ctx;
xmlNodePtr node;
xmlNsPtr ns;
/*
* load XPath expr as a file
*/
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
xmlSubstituteEntitiesDefault(1);
doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
if (doc == NULL) {
fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
return(NULL);
}
/*
* Check the document is of the right kind
*/
if(xmlDocGetRootElement(doc) == NULL) {
fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
xmlFreeDoc(doc);
return(NULL);
}
node = doc->children;
while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
node = node->next;
}
if(node == NULL) {
fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
xmlFreeDoc(doc);
return(NULL);
}
expr = xmlNodeGetContent(node);
if(expr == NULL) {
fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
xmlFreeDoc(doc);
return(NULL);
}
ctx = xmlXPathNewContext(parent_doc);
if(ctx == NULL) {
fprintf(stderr,"Error: unable to create new context\n");
xmlFree(expr);
xmlFreeDoc(doc);
return(NULL);
}
/*
* Register namespaces
*/
ns = node->nsDef;
while(ns != NULL) {
if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
xmlFree(expr);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
return(NULL);
}
ns = ns->next;
}
/*
* Evaluate xpath
*/
xpath = xmlXPathEvalExpression(expr, ctx);
if(xpath == NULL) {
fprintf(stderr,"Error: unable to evaluate xpath expression\n");
xmlFree(expr);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
return(NULL);
}
/* print_xpath_nodes(xpath->nodesetval); */
xmlFree(expr);
xmlXPathFreeContext(ctx);
xmlFreeDoc(doc);
return(xpath);
}
/*
* Macro used to grow the current buffer.
*/
#define xxx_growBufferReentrant() { \
buffer_size *= 2; \
buffer = (xmlChar **) \
xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
if (buffer == NULL) { \
perror("realloc failed"); \
return(NULL); \
} \
}
static xmlChar **
parse_list(xmlChar *str) {
xmlChar **buffer;
xmlChar **out = NULL;
int buffer_size = 0;
int len;
if(str == NULL) {
return(NULL);
}
len = xmlStrlen(str);
if((str[0] == '\'') && (str[len - 1] == '\'')) {
str[len - 1] = '\0';
str++;
}
/*
* allocate an translation buffer.
*/
buffer_size = 1000;
buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
if (buffer == NULL) {
perror("malloc failed");
return(NULL);
}
out = buffer;
while(*str != '\0') {
if (out - buffer > buffer_size - 10) {
int indx = out - buffer;
xxx_growBufferReentrant();
out = &buffer[indx];
}
(*out++) = str;
while(*str != ',' && *str != '\0') ++str;
if(*str == ',') *(str++) = '\0';
}
(*out) = NULL;
return buffer;
}
static int
c14nRunTest(const char* xml_filename, int with_comments, int mode,
const char* xpath_filename, const char *ns_filename,
const char* result_file) {
xmlDocPtr doc;
xmlXPathObjectPtr xpath = NULL;
xmlChar *result = NULL;
int ret;
xmlChar **inclusive_namespaces = NULL;
const char *nslist = NULL;
int nssize;
/*
* build an XML tree from a the file; we need to add default
* attributes and resolve all character and entities references
*/
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
xmlSubstituteEntitiesDefault(1);
doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
if (doc == NULL) {
fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
return(-1);
}
/*
* Check the document is of the right kind
*/
if(xmlDocGetRootElement(doc) == NULL) {
fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
xmlFreeDoc(doc);
return(-1);
}
/*
* load xpath file if specified
*/
if(xpath_filename) {
xpath = load_xpath_expr(doc, xpath_filename);
if(xpath == NULL) {
fprintf(stderr,"Error: unable to evaluate xpath expression\n");
xmlFreeDoc(doc);
return(-1);
}
}
if (ns_filename != NULL) {
if (loadMem(ns_filename, &nslist, &nssize)) {
fprintf(stderr,"Error: unable to evaluate xpath expression\n");
if(xpath != NULL) xmlXPathFreeObject(xpath);
xmlFreeDoc(doc);
return(-1);
}
inclusive_namespaces = parse_list((xmlChar *) nslist);
}
/*
* Canonical form
*/
/* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
ret = xmlC14NDocDumpMemory(doc,
(xpath) ? xpath->nodesetval : NULL,
mode, inclusive_namespaces,
with_comments, &result);
if (ret >= 0) {
if(result != NULL) {
if (compareFileMem(result_file, (const char *) result, ret)) {
fprintf(stderr, "Result mismatch for %s\n", xml_filename);
fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
ret = -1;
}
}
} else {
fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
ret = -1;
}
/*
* Cleanup
*/
if (result != NULL) xmlFree(result);
if(xpath != NULL) xmlXPathFreeObject(xpath);
if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
if (nslist != NULL) free((char *) nslist);
xmlFreeDoc(doc);
return(ret);
}
static int
c14nCommonTest(const char *filename, int with_comments, int mode,
const char *subdir) {
char buf[500];
char prefix[500];
const char *base;
int len;
char *result = NULL;
char *xpath = NULL;
char *ns = NULL;
int ret = 0;
base = baseFilename(filename);
len = strlen(base);
len -= 4;
memcpy(prefix, base, len);
prefix[len] = 0;
if (snprintf(buf, 499, "result/c14n/%s/%s", subdir, prefix) >= 499)
buf[499] = 0;
if (!checkTestFile(buf) && !update_results) {
fprintf(stderr, "Missing result file %s", buf);
return(-1);
}
result = strdup(buf);
if (snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir, prefix) >= 499)
buf[499] = 0;
if (checkTestFile(buf)) {
xpath = strdup(buf);
}
if (snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir, prefix) >= 499)
buf[499] = 0;
if (checkTestFile(buf)) {
ns = strdup(buf);
}
nb_tests++;
if (c14nRunTest(filename, with_comments, mode,
xpath, ns, result) < 0)
ret = 1;
if (result != NULL) free(result);
if (xpath != NULL) free(xpath);
if (ns != NULL) free(ns);
return(ret);
}
static int
c14nWithCommentTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
}
static int
c14nWithoutCommentTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
}
static int
c14nExcWithoutCommentTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
}
static int
c14n11WithoutCommentTest(const char *filename,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
}
#endif
#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
/************************************************************************
* *
* Catalog and threads test *
* *
************************************************************************/
/*
* mostly a cut and paste from testThreads.c
*/
#define MAX_ARGC 20
typedef struct {
const char *filename;
int okay;
} xmlThreadParams;
static const char *catalog = "test/threads/complex.xml";
static xmlThreadParams threadParams[] = {
{ "test/threads/abc.xml", 0 },
{ "test/threads/acb.xml", 0 },
{ "test/threads/bac.xml", 0 },
{ "test/threads/bca.xml", 0 },
{ "test/threads/cab.xml", 0 },
{ "test/threads/cba.xml", 0 },
{ "test/threads/invalid.xml", 0 }
};
static const unsigned int num_threads = sizeof(threadParams) /
sizeof(threadParams[0]);
#ifndef xmlDoValidityCheckingDefaultValue
#error xmlDoValidityCheckingDefaultValue is not a macro
#endif
#ifndef xmlGenericErrorContext
#error xmlGenericErrorContext is not a macro
#endif
static void *
thread_specific_data(void *private_data)
{
xmlDocPtr myDoc;
xmlThreadParams *params = (xmlThreadParams *) private_data;
const char *filename = params->filename;
int okay = 1;
if (!strcmp(filename, "test/threads/invalid.xml")) {
xmlDoValidityCheckingDefaultValue = 0;
xmlGenericErrorContext = stdout;
} else {
xmlDoValidityCheckingDefaultValue = 1;
xmlGenericErrorContext = stderr;
}
#ifdef LIBXML_SAX1_ENABLED
myDoc = xmlParseFile(filename);
#else
myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
#endif
if (myDoc) {
xmlFreeDoc(myDoc);
} else {
printf("parse failed\n");
okay = 0;
}
if (!strcmp(filename, "test/threads/invalid.xml")) {
if (xmlDoValidityCheckingDefaultValue != 0) {
printf("ValidityCheckingDefaultValue override failed\n");
okay = 0;
}
if (xmlGenericErrorContext != stdout) {
printf("xmlGenericErrorContext override failed\n");
okay = 0;
}
} else {
if (xmlDoValidityCheckingDefaultValue != 1) {
printf("ValidityCheckingDefaultValue override failed\n");
okay = 0;
}
if (xmlGenericErrorContext != stderr) {
printf("xmlGenericErrorContext override failed\n");
okay = 0;
}
}
params->okay = okay;
return(NULL);
}
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#include <string.h>
#define TEST_REPEAT_COUNT 500
static HANDLE tid[MAX_ARGC];
static DWORD WINAPI
win32_thread_specific_data(void *private_data)
{
thread_specific_data(private_data);
return(0);
}
static int
testThread(void)
{
unsigned int i, repeat;
BOOL ret;
int res = 0;
xmlInitParser();
for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
xmlLoadCatalog(catalog);
nb_tests++;
for (i = 0; i < num_threads; i++) {
tid[i] = (HANDLE) - 1;
}
for (i = 0; i < num_threads; i++) {
DWORD useless;
tid[i] = CreateThread(NULL, 0,
win32_thread_specific_data,
(void *) &threadParams[i], 0,
&useless);
if (tid[i] == NULL) {
fprintf(stderr, "CreateThread failed\n");
return(1);
}
}
if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
WAIT_FAILED) {
fprintf(stderr, "WaitForMultipleObjects failed\n");
return(1);
}
for (i = 0; i < num_threads; i++) {
DWORD exitCode;
ret = GetExitCodeThread(tid[i], &exitCode);
if (ret == 0) {
fprintf(stderr, "GetExitCodeThread failed\n");
return(1);
}
CloseHandle(tid[i]);
}
xmlCatalogCleanup();
for (i = 0; i < num_threads; i++) {
if (threadParams[i].okay == 0) {
fprintf(stderr, "Thread %d handling %s failed\n",
i, threadParams[i].filename);
res = 1;
}
}
}
return (res);
}
#elif defined __BEOS__
#include <OS.h>
static thread_id tid[MAX_ARGC];
static int
testThread(void)
{
unsigned int i, repeat;
status_t ret;
int res = 0;
xmlInitParser();
for (repeat = 0; repeat < 500; repeat++) {
xmlLoadCatalog(catalog);
for (i = 0; i < num_threads; i++) {
tid[i] = (thread_id) - 1;
}
for (i = 0; i < num_threads; i++) {
tid[i] =
spawn_thread(thread_specific_data, "xmlTestThread",
B_NORMAL_PRIORITY, (void *) &threadParams[i]);
if (tid[i] < B_OK) {
fprintf(stderr, "beos_thread_create failed\n");
return (1);
}
printf("beos_thread_create %d -> %d\n", i, tid[i]);
}
for (i = 0; i < num_threads; i++) {
void *result;
ret = wait_for_thread(tid[i], &result);
printf("beos_thread_wait %d -> %d\n", i, ret);
if (ret != B_OK) {
fprintf(stderr, "beos_thread_wait failed\n");
return (1);
}
}
xmlCatalogCleanup();
ret = B_OK;
for (i = 0; i < num_threads; i++)
if (threadParams[i].okay == 0) {
printf("Thread %d handling %s failed\n", i,
threadParams[i].filename);
ret = B_ERROR;
}
}
if (ret != B_OK)
return(1);
return (0);
}
#elif defined HAVE_PTHREAD_H
#include <pthread.h>
static pthread_t tid[MAX_ARGC];
static int
testThread(void)
{
unsigned int i, repeat;
int ret;
int res = 0;
xmlInitParser();
for (repeat = 0; repeat < 500; repeat++) {
xmlLoadCatalog(catalog);
nb_tests++;
for (i = 0; i < num_threads; i++) {
tid[i] = (pthread_t) - 1;
}
for (i = 0; i < num_threads; i++) {
ret = pthread_create(&tid[i], 0, thread_specific_data,
(void *) &threadParams[i]);
if (ret != 0) {
fprintf(stderr, "pthread_create failed\n");
return (1);
}
}
for (i = 0; i < num_threads; i++) {
void *result;
ret = pthread_join(tid[i], &result);
if (ret != 0) {
fprintf(stderr, "pthread_join failed\n");
return (1);
}
}
xmlCatalogCleanup();
for (i = 0; i < num_threads; i++)
if (threadParams[i].okay == 0) {
fprintf(stderr, "Thread %d handling %s failed\n",
i, threadParams[i].filename);
res = 1;
}
}
return (res);
}
#else
static int
testThread(void)
{
fprintf(stderr,
"Specific platform thread support not detected\n");
return (-1);
}
#endif
static int
threadsTest(const char *filename ATTRIBUTE_UNUSED,
const char *resul ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
return(testThread());
}
#endif
/************************************************************************
* *
* Tests Descriptions *
* *
************************************************************************/
static
testDesc testDescriptions[] = {
{ "XML regression tests" ,
oldParseTest, "./test/*", "result/", "", NULL,
0 },
{ "XML regression tests on memory" ,
memParseTest, "./test/*", "result/", "", NULL,
0 },
{ "XML entity subst regression tests" ,
noentParseTest, "./test/*", "result/noent/", "", NULL,
XML_PARSE_NOENT },
{ "XML Namespaces regression tests",
errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
0 },
{ "Error cases regression tests",
errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
0 },
{ "Error cases regression tests from file descriptor",
fdParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
0 },
{ "Error cases regression tests with entity substitution",
errParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".ent",
XML_PARSE_NOENT },
{ "Error cases regression tests (old 1.0)",
errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
XML_PARSE_OLD10 },
#ifdef LIBXML_READER_ENABLED
{ "Error cases stream regression tests",
streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
0 },
{ "Reader regression tests",
streamParseTest, "./test/*", "result/", ".rdr", NULL,
0 },
{ "Reader entities substitution regression tests",
streamParseTest, "./test/*", "result/", ".rde", NULL,
XML_PARSE_NOENT },
{ "Reader on memory regression tests",
streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
0 },
{ "Walker regression tests",
walkerParseTest, "./test/*", "result/", ".rdr", NULL,
0 },
#endif
#ifdef LIBXML_SAX1_ENABLED
{ "SAX1 callbacks regression tests" ,
saxParseTest, "./test/*", "result/", ".sax", NULL,
XML_PARSE_SAX1 },
#endif
{ "SAX2 callbacks regression tests" ,
saxParseTest, "./test/*", "result/", ".sax2", NULL,
0 },
{ "SAX2 callbacks regression tests with entity substitution" ,
saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
XML_PARSE_NOENT },
#ifdef LIBXML_PUSH_ENABLED
{ "XML push regression tests" ,
pushParseTest, "./test/*", "result/", "", NULL,
0 },
#endif
#ifdef LIBXML_HTML_ENABLED
{ "HTML regression tests" ,
errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
XML_PARSE_HTML },
{ "HTML regression tests from file descriptor",
fdParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
XML_PARSE_HTML },
#ifdef LIBXML_PUSH_ENABLED
{ "Push HTML regression tests" ,
pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
XML_PARSE_HTML },
#endif
{ "HTML SAX regression tests" ,
saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
XML_PARSE_HTML },
#endif
#ifdef LIBXML_VALID_ENABLED
{ "Valid documents regression tests" ,
errParseTest, "./test/VCM/*", NULL, NULL, NULL,
XML_PARSE_DTDVALID },
{ "Validity checking regression tests" ,
errParseTest, "./test/VC/*", "result/VC/", NULL, "",
XML_PARSE_DTDVALID },
#ifdef LIBXML_READER_ENABLED
{ "Streaming validity checking regression tests" ,
streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
XML_PARSE_DTDVALID },
{ "Streaming validity error checking regression tests" ,
streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
XML_PARSE_DTDVALID },
#endif
{ "General documents valid regression tests" ,
errParseTest, "./test/valid/*", "result/valid/", "", ".err",
XML_PARSE_DTDVALID },
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
{ "XInclude regression tests" ,
errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
/* Ignore errors at this point ".err", */
XML_PARSE_XINCLUDE },
#ifdef LIBXML_READER_ENABLED
{ "XInclude xmlReader regression tests",
streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
/* Ignore errors at this point ".err", */
NULL, XML_PARSE_XINCLUDE },
#endif
{ "XInclude regression tests stripping include nodes" ,
errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
/* Ignore errors at this point ".err", */
XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
#ifdef LIBXML_READER_ENABLED
{ "XInclude xmlReader regression tests stripping include nodes",
streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
/* Ignore errors at this point ".err", */
NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
#endif
#endif
#ifdef LIBXML_XPATH_ENABLED
#ifdef LIBXML_DEBUG_ENABLED
{ "XPath expressions regression tests" ,
xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
0 },
{ "XPath document queries regression tests" ,
xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
0 },
#ifdef LIBXML_XPTR_ENABLED
{ "XPointer document queries regression tests" ,
xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
0 },
#endif
{ "xml:id regression tests" ,
xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
0 },
#endif
#endif
{ "URI parsing tests" ,
uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
0 },
{ "URI base composition tests" ,
uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
0 },
{ "Path URI conversion tests" ,
uriPathTest, NULL, NULL, NULL, NULL,
0 },
#ifdef LIBXML_SCHEMAS_ENABLED
{ "Schemas regression tests" ,
schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
0 },
{ "Relax-NG regression tests" ,
rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
XML_PARSE_DTDATTR | XML_PARSE_NOENT },
#ifdef LIBXML_READER_ENABLED
{ "Relax-NG streaming regression tests" ,
rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
XML_PARSE_DTDATTR | XML_PARSE_NOENT },
#endif
#endif
#ifdef LIBXML_PATTERN_ENABLED
#ifdef LIBXML_READER_ENABLED
{ "Pattern regression tests" ,
patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
0 },
#endif
#endif
#ifdef LIBXML_C14N_ENABLED
{ "C14N with comments regression tests" ,
c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
0 },
{ "C14N without comments regression tests" ,
c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
0 },
{ "C14N exclusive without comments regression tests" ,
c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
0 },
{ "C14N 1.1 without comments regression tests" ,
c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
0 },
#endif
#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
{ "Catalog and Threads regression tests" ,
threadsTest, NULL, NULL, NULL, NULL,
0 },
#endif
{NULL, NULL, NULL, NULL, NULL, NULL, 0}
};
/************************************************************************
* *
* The main code driving the tests *
* *
************************************************************************/
static int
launchTests(testDescPtr tst) {
int res = 0, err = 0;
size_t i;
char *result;
char *error;
int mem;
xmlCharEncodingHandlerPtr ebcdicHandler, eucJpHandler;
ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC);
eucJpHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EUC_JP);
if (tst == NULL) return(-1);
if (tst->in != NULL) {
glob_t globbuf;
globbuf.gl_offs = 0;
glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
for (i = 0;i < globbuf.gl_pathc;i++) {
if (!checkTestFile(globbuf.gl_pathv[i]))
continue;
if (((ebcdicHandler == NULL) &&
(strstr(globbuf.gl_pathv[i], "ebcdic") != NULL)) ||
((eucJpHandler == NULL) &&
(strstr(globbuf.gl_pathv[i], "icu_parse_test") != NULL)))
continue;
if (tst->suffix != NULL) {
result = resultFilename(globbuf.gl_pathv[i], tst->out,
tst->suffix);
if (result == NULL) {
fprintf(stderr, "Out of memory !\n");
fatalError();
}
} else {
result = NULL;
}
if (tst->err != NULL) {
error = resultFilename(globbuf.gl_pathv[i], tst->out,
tst->err);
if (error == NULL) {
fprintf(stderr, "Out of memory !\n");
fatalError();
}
} else {
error = NULL;
}
if ((result) &&(!checkTestFile(result)) && !update_results) {
fprintf(stderr, "Missing result file %s\n", result);
} else if ((error) &&(!checkTestFile(error)) && !update_results) {
fprintf(stderr, "Missing error file %s\n", error);
} else {
mem = xmlMemUsed();
extraMemoryFromResolver = 0;
testErrorsSize = 0;
testErrors[0] = 0;
res = tst->func(globbuf.gl_pathv[i], result, error,
tst->options | XML_PARSE_COMPACT);
xmlResetLastError();
if (res != 0) {
fprintf(stderr, "File %s generated an error\n",
globbuf.gl_pathv[i]);
nb_errors++;
err++;
}
else if (xmlMemUsed() != mem) {
if ((xmlMemUsed() != mem) &&
(extraMemoryFromResolver == 0)) {
fprintf(stderr, "File %s leaked %d bytes\n",
globbuf.gl_pathv[i], xmlMemUsed() - mem);
nb_leaks++;
err++;
}
}
testErrorsSize = 0;
}
if (result)
free(result);
if (error)
free(error);
}
globfree(&globbuf);
} else {
testErrorsSize = 0;
testErrors[0] = 0;
extraMemoryFromResolver = 0;
res = tst->func(NULL, NULL, NULL, tst->options);
if (res != 0) {
nb_errors++;
err++;
}
}
xmlCharEncCloseFunc(ebcdicHandler);
xmlCharEncCloseFunc(eucJpHandler);
return(err);
}
static int verbose = 0;
static int tests_quiet = 0;
static int
runtest(int i) {
int ret = 0, res;
int old_errors, old_tests, old_leaks;
old_errors = nb_errors;
old_tests = nb_tests;
old_leaks = nb_leaks;
if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
printf("## %s\n", testDescriptions[i].desc);
res = launchTests(&testDescriptions[i]);
if (res != 0)
ret++;
if (verbose) {
if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
printf("Ran %d tests, no errors\n", nb_tests - old_tests);
else
printf("Ran %d tests, %d errors, %d leaks\n",
nb_tests - old_tests,
nb_errors - old_errors,
nb_leaks - old_leaks);
}
return(ret);
}
int
main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
int i, a, ret = 0;
int subset = 0;
#if defined(_WIN32) && !defined(__CYGWIN__)
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
initializeLibxml2();
for (a = 1; a < argc;a++) {
if (!strcmp(argv[a], "-v"))
verbose = 1;
else if (!strcmp(argv[a], "-u"))
update_results = 1;
else if (!strcmp(argv[a], "-quiet"))
tests_quiet = 1;
else if (!strcmp(argv[a], "--out"))
temp_directory = argv[++a];
else {
for (i = 0; testDescriptions[i].func != NULL; i++) {
if (strstr(testDescriptions[i].desc, argv[a])) {
ret += runtest(i);
subset++;
}
}
}
}
if (subset == 0) {
for (i = 0; testDescriptions[i].func != NULL; i++) {
ret += runtest(i);
}
}
if ((nb_errors == 0) && (nb_leaks == 0)) {
ret = 0;
printf("Total %d tests, no errors\n",
nb_tests);
} else {
ret = 1;
printf("Total %d tests, %d errors, %d leaks\n",
nb_tests, nb_errors, nb_leaks);
}
xmlCleanupParser();
xmlMemoryDump();
return(ret);
}
#else /* ! LIBXML_OUTPUT_ENABLED */
int
main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
return(1);
}
#endif
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化