/* * PDFedit - free program for PDF document manipulation. * Copyright (C) 2006, 2007 PDFedit team: Michal Hocko, * Miroslav Jahoda, * Jozef Misutka, * Martin Petricek * * Project is hosted on http://sourceforge.net/projects/pdfedit */ // vim:tabstop=4:shiftwidth=4:noexpandtab:textwidth=80 /* * $RCSfile: testcpdf.cc,v $ * * $Log: testcpdf.cc,v $ * Revision 1.36 2007/02/04 20:17:03 mstsxfx * Common Licence comment for all cc and h files available in doc/licence_header * file and its content to all cc and h files in src/{gui,kernel,utils} * directories. * Xpdf code, QSA and QOutputDevice code are not touched * * Revision 1.35 2006/10/30 21:24:46 hockm0bm * test case for inserting page to an empty document * * Revision 1.34 2006/08/09 20:47:35 hockm0bm * indirectPropertyTC minor changes * * Revision 1.33 2006/06/27 17:26:24 hockm0bm * cloneTC skips linearized pdfs * * Revision 1.32 2006/06/25 17:55:43 hockm0bm * * pageManipulationTC * - TC07 fixed (all pages are considered when collecting isDescendants) * * Revision 1.31 2006/06/22 18:47:27 hockm0bm * * deprecated functions replaced * * new test cases for ambiguous page tree * * Revision 1.30 2006/06/19 17:31:56 hockm0bm * pageManipulationTC almost finished * - most of test cases are done and successfull * - CPdf interface page manipulation well tested * * Revision 1.29 2006/06/17 15:04:49 misuj1am * * -- include rem/add * * Revision 1.28 2006/06/11 22:17:23 hockm0bm * TODOs * * Revision 1.27 2006/06/11 22:11:46 hockm0bm * testManipulationTC * - new test cases for intermediate node (insert new internode, * replace internode by another one) * * Revision 1.26 2006/06/11 14:36:10 hockm0bm * sync with getNodePosition signature change * * Revision 1.25 2006/06/06 09:47:56 hockm0bm * pageIterationTC checks all iterator methods for pages with isChanged * - test DOESN'T PASS - CPage may do changes when it is created (adds * inherited attributes if not present directly in dictionary) * * Revision 1.24 2006/06/05 22:41:34 hockm0bm * * example implementation of IProgressBar * * DelinearizatorTC uses * * ProgressBar and ProgressObserver test * * Revision 1.23 2006/06/05 08:57:33 hockm0bm * refactoring CObjectSimple * - getPropertyValue -> getValue * - writeValue -> setValue * * Revision 1.22 2006/05/30 22:30:48 hockm0bm * cloneTC corrected * - sets back to the newest revision after testing to get given pdf * instance to same state as it was given to the function * * Revision 1.21 2006/05/30 17:31:18 hockm0bm * cloneTC method added * - creates clone of each revision * * Revision 1.20 2006/05/24 19:34:03 hockm0bm * pageIterationTC mem leak fixed * - fakeXpdfDict is deallocated now * * Revision 1.19 2006/05/16 18:56:42 hockm0bm * test for Delinearizator with observer (ProgressBar) * * Revision 1.18 2006/05/15 18:31:46 hockm0bm * isEncrypted testing * * Revision 1.17 2006/05/13 22:12:26 hockm0bm * tests updated * - addIndirectProperty tested quite well now and seems that new * implementation is correct finally * * Revision 1.16 2006/05/10 20:38:02 hockm0bm * isChanged checked * * Revision 1.15 2006/05/06 21:17:38 hockm0bm * removed additional code * * Revision 1.14 2006/05/06 08:56:57 hockm0bm * tests improved - all of them are successfull - everything tested seems to work * * Revision 1.13 2006/04/28 17:18:17 hockm0bm * * instancingTC * - just skeleton * * revisionsTC removed from pdfs loop in Test method * * indirectPropertyTC * - first test cases * * Revision 1.12 2006/04/27 18:35:50 hockm0bm * revisionsTC new test cases * - changeRevision seams to be tested quite well * * Revision 1.11 2006/04/25 02:28:05 misuj1am * * -- improved cpage, cstream, tests * * Revision 1.10 2006/04/23 23:20:40 misuj1am * * -- improved: zero page (incorrect) document handling * * Revision 1.9 2006/04/23 22:09:48 hockm0bm * * pageIterationTC finished * - all tests are ok * * pageManipulationTC * - almost finised (interNode removing is TODO) * - all tests until now are ok * * revisionsTC * - just skeleton * * Revision 1.8 2006/04/23 11:16:48 hockm0bm * pageManipulationTC added * - insertPage, removePage test cases * * Revision 1.7 2006/04/22 19:46:12 hockm0bm * test case Test added to CPPUnit tests of CPdf suite * * Revision 1.6 2006/04/22 19:32:20 hockm0bm * * old test style replaced by CPPUINT TestCPdf class * * TestCPdf::pageIterationTC method implemented * * * */ #include "testmain.h" #include "testcpdf.h" #include "../factories.h" #include "../cobjecthelpers.h" #include "../cpdf.h" #include "../pdfwriter.h" #include "utils/delinearizator.h" using namespace pdfobjects; using namespace utils; using namespace observer; using namespace boost; #define TEST_FILE "../../doc/zadani.pdf" class ProgressBar:public IProgressBar { int maxStep; ostream & out; int displayStep; float lastPerc; public: ProgressBar(ostream & str, int step=10):out(str), displayStep(step) { } virtual ~ProgressBar(){} virtual void start() { out << "Starting progress" << endl; lastPerc=0; } virtual void finish() { out << "Progress ended" << endl; } virtual void update(int step) { float perc=(float)(100*step)/(float)maxStep; if(perc>=lastPerc+displayStep) { out << perc << "% done" <isLinearized()) { printf("%s is not suitable for this test, because file is linearized\n", originalFile.c_str()); return; } char suffix[13]; memset(suffix, '\0', sizeof(suffix)); snprintf(suffix, sizeof(suffix)-1, "%u_clone.pdf", 0); string file=originalFile+suffix; printf("TC01:\tCloning of first (the newest one) revision. Output file=%s\n", file.c_str()); FILE * cloneFile=fopen(file.c_str(), "w"); pdf->clone(cloneFile); fclose(cloneFile); printf("TC02:\tCloning of later revisions.\n"); for(CPdf::revision_t rev=1; revgetRevisionsCount(); rev++) { try { printf("\t\t%d. revision clone. Output file=%s\n", rev, file.c_str()); pdf->changeRevision(rev); snprintf(suffix, sizeof(suffix)-1, "%u_clone.pdf", rev); file=originalFile+suffix; cloneFile=fopen(file.c_str(), "w"); pdf->clone(cloneFile); fclose(cloneFile); }catch(NotImplementedException & e) { printf("\t\tData not suitable for this test. Revision changing is not supported.\n"); } } // gets back to the newest revision pdf->changeRevision(0); printf("TC03:\t cloning doesn't change content test\n"); CPPUNIT_ASSERT(!pdf->isChanged()); } void pageIterationTC(CPdf * pdf) { using namespace boost; using namespace utils; printf("%s\n", __FUNCTION__); CPPUNIT_ASSERT(!pdf->isChanged()); // getPage and getPagePosition must match for all pages printf("TC01:\tPageCount, getPage, getPagePosition\n"); size_t pageCount=pdf->getPageCount(); CPPUNIT_ASSERT(!pdf->isChanged()); if (0 == pageCount) return; for(size_t i=1; i<=pageCount; i++) { shared_ptr page=pdf->getPage(i); CPPUNIT_ASSERT(!pdf->isChanged()); size_t pos=pdf->getPagePosition(page); CPPUNIT_ASSERT(!pdf->isChanged()); CPPUNIT_ASSERT(i==pos); } // getPage, getNextPage, getPrevPage must match for all pages printf("TC02:\tgetPage, getNextPage, getPrevPage\n"); for(size_t i=1; i<=pageCount; i++) { shared_ptr pos=pdf->getPage(i); if(i>1) { shared_ptr prev=pdf->getPage(i-1); CPPUNIT_ASSERT(pdf->getPrevPage(pos)==prev); } if(i next=pdf->getPage(i+1); CPPUNIT_ASSERT(pdf->getNextPage(pos)==next); } CPPUNIT_ASSERT(!pdf->isChanged()); } printf("TC03:\tgetPage, getFirstPage and getLastPage test\n"); if(pdf->getPageCount()) { CPPUNIT_ASSERT(pdf->getPage(1)==pdf->getFirstPage()); CPPUNIT_ASSERT(pdf->getPage(pdf->getPageCount())==pdf->getLastPage()); } CPPUNIT_ASSERT(!pdf->isChanged()); // out of range page positions must throw printf("TC04:\tgetPage, getNextPage, getPrevPage out of range test\n"); // 0 page is out of range try { pdf->getPage(0); CPPUNIT_FAIL("getPage(0) should have failed"); }catch(PageNotFoundException &e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); // pageCount + 1 is out of range try { pdf->getPage(pdf->getPageCount()+1); CPPUNIT_FAIL("getPage(%d) should have filed"); }catch(PageNotFoundException &e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); // getPrevPage(getFirstPage()) is out of range try { pdf->getPrevPage(pdf->getFirstPage()); CPPUNIT_FAIL("getPrevPage(getFirstPage()) should have failed"); }catch(PageNotFoundException &e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); // getNextPage(getLastPage()) is out of range try { pdf->getNextPage(pdf->getLastPage()); CPPUNIT_FAIL("getNextPage(getLastPage()) should have failed"); }catch(PageNotFoundException &e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); printf("TC05:\thasNextPage, hasPrevPage test\n"); if(pdf->getPageCount()) { // first page hasPrevPage should return false CPPUNIT_ASSERT(!pdf->hasPrevPage(pdf->getFirstPage())); CPPUNIT_ASSERT(!pdf->isChanged()); // last page hasNextPage should return false CPPUNIT_ASSERT(!pdf->hasNextPage(pdf->getLastPage())); CPPUNIT_ASSERT(!pdf->isChanged()); // hasNextPage and hasPrevPage should return true for all other // pages for(size_t i=2; ihasPrevPage(pdf->getPage(i))); CPPUNIT_ASSERT(!pdf->isChanged()); CPPUNIT_ASSERT(pdf->hasNextPage(pdf->getPage(i))); CPPUNIT_ASSERT(!pdf->isChanged()); } } printf("TC06:\tgetPagePosition, getNextPage, getPrevPage with fake page parameter test\n"); // page from empty page dictionary - no pdf specified inside shared_ptr fakeDict1(CDictFactory::getInstance()); shared_ptr fake1(new CPage(fakeDict1)); Object fakeXpdfDict; XRef * fakeXref=pdf->getCXref(); fakeXpdfDict.initDict(fakeXref); IndiRef fakeIndiRef(10, 0); shared_ptr fakeDict2(CDictFactory::getInstance(*pdf, fakeIndiRef, fakeXpdfDict)); shared_ptr fake2(new CPage(fakeDict2)); fakeXpdfDict.free(); // getPagePosition should fail on both fakes try { pdf->getPagePosition(fake1); CPPUNIT_FAIL("getPagePosition(fake1) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); try { pdf->getPagePosition(fake2); CPPUNIT_FAIL("getPagePosition(fake2) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); // getPrevPage should fail on both fakes try { pdf->getPrevPage(fake1); CPPUNIT_FAIL("getPrevPage(fake1) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); try { pdf->getPrevPage(fake2); CPPUNIT_FAIL("getPrevPage(fake2) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); // getNextPage should fail on both fakes try { pdf->getNextPage(fake1); CPPUNIT_FAIL("getNextPage(fake1) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } CPPUNIT_ASSERT(!pdf->isChanged()); try { pdf->getNextPage(fake2); CPPUNIT_FAIL("getNextPage(fake2) should have failed"); }catch(PageNotFoundException & e) { // ok, exception has been thrown } // no change made to document CPPUNIT_ASSERT(!pdf->isChanged()); } void pageManipulationTC(CPdf * pdf) { using namespace boost; using namespace utils; printf("%s\n", __FUNCTION__); size_t pageCount=pdf->getPageCount(); if (0 == pageCount) { printf("TC01:\tinsertPage to an empty document results in 1 total pages\n"); CPdf * test_doc = getTestCPdf(TEST_FILE); pdf->insertPage(test_doc->getFirstPage(), 1); CPPUNIT_ASSERT(pdf->getPageCount()==1); test_doc->close(); return; } printf("TC01:\tremovePage, insertPage changes pageCount\n"); shared_ptr page=pdf->getPage(1); // remove page implies pageCount decrementation test pdf->removePage(1); CPPUNIT_ASSERT(pageCount-1==pdf->getPageCount()); // insert page implies pageCount incrementation // and newPage must be different instance than original one shared_ptr newPage=pdf->insertPage(page, 1); CPPUNIT_ASSERT(pageCount==pdf->getPageCount()); printf("TC02:\tinsertPage returns different instance than parameter\n"); CPPUNIT_ASSERT(page!=newPage); CPPUNIT_ASSERT(page->getDictionary()!=newPage->getDictionary()); // page count is same as in original file now printf("TC03:\tremovePage out of range test\n"); // remove from 0 page should fail try { pdf->removePage(0); CPPUNIT_FAIL("removePage should have failed"); }catch(PageNotFoundException & e) { // everything ok } // remove from pageCount()+1 should fail try { pdf->removePage(pdf->getPageCount()+1); CPPUNIT_FAIL("removePage should have failed"); }catch(PageNotFoundException & e) { // everything ok } printf("TC04:\tinsert page never causes ambiguous page tree\n"); // inserts first page again and tries to to call getNodePosition shared_ptr addedPage=pdf->insertPage(pdf->getFirstPage(), 1); size_t pos=getNodePosition(*pdf, addedPage->getDictionary(), NULL); CPPUNIT_ASSERT(pos==1); // removes added page pdf->removePage(pos); printf("TC05:\tremoved page is no longer available test\n"); // try to remove last page shared_ptr removedPage=pdf->getLastPage(); IndiRef removedPageRef=removedPage->getDictionary()->getIndiRef(); pos=pdf->getPagePosition(removedPage); CPPUNIT_ASSERT(pos==pdf->getPageCount()); pdf->removePage(pdf->getPageCount()); // FIXME uncoment when ready //CPPUNIT_ASSERT(! removePage->isValid()); try { pos=pdf->getPagePosition(removedPage); CPPUNIT_FAIL("getPagePosition on removed page should have failed."); }catch(PageNotFoundException & e) { /* ok, it should have fail */ } // restore to previous state pdf->insertPage(removedPage, pos); printf("TC06:\tremoving page's dictionary invalidates page\n"); pos=pdf->getPageCount()/2; // if we have just one page, use it if(!pos) pos=1; page=pdf->getPage(pos); shared_ptr pageDict=page->getDictionary(); shared_ptr pageRef(CRefFactory::getInstance(pageDict->getIndiRef())); // gets parent of page dictionary and removes reference of this page // from Kids array shared_ptr parentRef=IProperty::getSmartCObjectPtr(pageDict->getProperty("Parent")); shared_ptr parentDict=IProperty::getSmartCObjectPtr( pdf->getIndirectProperty(getValueFromSimple(parentRef))); shared_ptr kidsArray=IProperty::getSmartCObjectPtr( parentDict->getProperty("Kids")); vector positions; getPropertyId >(kidsArray, pageRef, positions); CPPUNIT_ASSERT(positions.size()>0); // we know that position is not ambiguous so use 1st in positions array kidsArray->delProperty(positions[0]); // FIXME uncoment when ready //CPPUNIT_ASSERT(! page->isValid()); try { pdf->getPagePosition(page); CPPUNIT_FAIL("getPagePosition on removed page should have failed"); }catch(PageNotFoundException & e) { /* ok, it should fail */ } // inserts back removed page pdf->insertPage(page, pos); // uses 1st internode kid from page tree root dictionary shared_ptr interNode; shared_ptr interNodeCRef; shared_ptr rootDict=getPageTreeRoot(*pdf); shared_ptr rootKidsProp=rootDict->getProperty("Kids"); shared_ptr rootKids; if(isRef(rootKidsProp)) { try { rootKids=getCObjectFromRef(rootKidsProp); }catch(CObjectException & e) { } } else if(isArray(rootKidsProp)) rootKids=IProperty::getSmartCObjectPtr(rootKidsProp); size_t interPos=0; if(!rootKids.get()) { printf("\t\tKids array has bad type, ignoring"); }else { vector > children; rootKids->_getAllChildObjects(children); size_t index=0; for(vector >::iterator i=children.begin(); i!=children.end(); i++, index++) { shared_ptr child=*i; if(getNodeType(child)>=InterNode) { interNode=getCObjectFromRef(child); interNodeCRef=IProperty::getSmartCObjectPtr(child); interPos=index; break; } } } // creates new intermediate node with no children just for // simulation shared_ptr fakeInterNode(CDictFactory::getInstance()); shared_ptr type(CNameFactory::getInstance("Pages")); fakeInterNode->addProperty("Type", *type); IndiRef fakeInterRef=pdf->addIndirectProperty(fakeInterNode); size_t fakeInterLeafCount=0; if(!interNode) // no internode available printf("\t\tThis file is not suitable for this test\n"); else { // collects all descendants from interNode vector > descendants; size_t pageCount=pdf->getPageCount(); for(size_t i=1; i<=pageCount; i++) { shared_ptr page=pdf->getPage(i); if(isDescendant(*pdf, interNode->getIndiRef(), page->getDictionary())) descendants.push_back(page); } // all descendants are collected, we can remove interNode reference // from rootKids printf("TC07:\tremovig inter node removes all pages under\n"); rootKids->delProperty(interPos); // page count has to be decreased by descendants.size() CPPUNIT_ASSERT(pdf->getPageCount()+descendants.size()==pageCount); // all pages from descendants are not available for(vector >::iterator i=descendants.begin();i!=descendants.end(); i++) { try { pos=pdf->getPagePosition(*i); CPPUNIT_FAIL("getPagePosition on removed page should have failed"); }catch(PageNotFoundException &e) { /* ok */ } } // inserts back interNode to 1st position in root kids array // currently first page should be at 1+getKidsCount (if there is any // page); printf("TC08:\tinserting intermediate node test.\n"); shared_ptr firstPage, lastPage; size_t currPageCount=pdf->getPageCount(); if(currPageCount) { firstPage=pdf->getFirstPage(); lastPage=pdf->getLastPage(); } size_t interNodeLeafCount=getKidsCount(interNode,NULL); rootKids->addProperty(0, *interNodeCRef); CPPUNIT_ASSERT(currPageCount + interNodeLeafCount == pdf->getPageCount()); if(firstPage.get()) CPPUNIT_ASSERT(pdf->getPagePosition(firstPage) == interNodeLeafCount + 1); if(lastPage.get()) CPPUNIT_ASSERT(pdf->getPagePosition(lastPage) == interNodeLeafCount + currPageCount); printf("TC09:\treplacing intermediate node by another intermediate node\n"); // gets CRef of firts root's kid (one we have inserted) shared_ptr replaceElement=IProperty::getSmartCObjectPtr(rootKids->getProperty(0)); // change value in replaceElement to contain reference to newly // created fake intermediate node currPageCount=pdf->getPageCount(); replaceElement->setValue(fakeInterRef); CPPUNIT_ASSERT(pdf->getPageCount() == currPageCount - interNodeLeafCount + fakeInterLeafCount); if(firstPage.get()) CPPUNIT_ASSERT(pdf->getPagePosition(firstPage) == 1 + fakeInterLeafCount); if(lastPage.get()) CPPUNIT_ASSERT(pdf->getPagePosition(lastPage) == currPageCount - interNodeLeafCount + fakeInterLeafCount); // sets value back with setProperty rootKids->setProperty(0, *interNodeCRef); // TODO Kids array as reference to array/mess, printf("TC13:\tambiguous page tree test - ambiguous intermediate node\n"); // inserts reference to interNode to rootKids - this produces // ambiguous page tree for this intermediate node - despite that all // pages should be accessible CPPUNIT_ASSERT(getValueFromSimple(interNodeCRef)==interNode->getIndiRef()); currPageCount=pdf->getPageCount(); rootKids->addProperty(*interNodeCRef); CPPUNIT_ASSERT(pdf->getPageCount()==currPageCount+getKidsCount(interNode,NULL)); try { getNodePosition(*pdf, interNode, NULL); CPPUNIT_FAIL("getNodePosition should have failed"); }catch(AmbiguousPageTreeException & e) { /* ok */ } try { shared_ptr page=pdf->getFirstPage(); while(pdf->hasNextPage(page)) page=pdf->getNextPage(page); }catch(exception & e) { CPPUNIT_FAIL("page iteration methods shouldn't failed"); } // removes last (ambiguous element) rootKids->delProperty(rootKids->getPropertyCount()-1); CPPUNIT_ASSERT(pdf->getPageCount()==currPageCount); printf("TC14:\tambiguous page tree test - ambiguous leaf node\n"); // gets parent of first page firstPage=pdf->getFirstPage(); shared_ptr parentDict=getCObjectFromRef( firstPage->getDictionary()->getProperty("Parent") ); shared_ptr parentKids=IProperty::getSmartCObjectPtr( parentDict->getProperty("Kids") ); shared_ptr firstPageRef(CRefFactory::getInstance( firstPage->getDictionary()->getIndiRef()) ); currPageCount=pdf->getPageCount(); parentKids->addProperty(*firstPageRef); try { pdf->getPagePosition(firstPage); CPPUNIT_FAIL("getPagePosition should have failed on ambiguous page."); }catch(PageNotFoundException & e) { /* ok */ } try { getNodePosition(*pdf, firstPage->getDictionary(), NULL); CPPUNIT_FAIL("getNodePosition should have failed for ambiguous page dictionary."); }catch(AmbiguousPageTreeException & e) { /* ok */ } try { for(size_t pos=1; posgetPageCount(); pos++) page=pdf->getPage(pos); }catch(exception & e) { CPPUNIT_FAIL("page iteration methods shouldn't failed"); } // page is ambiguous but total page count should have increased CPPUNIT_ASSERT(pdf->getPageCount()==currPageCount+1); // gets back to unambiguous state parentKids->delProperty(parentKids->getPropertyCount()-1); CPPUNIT_ASSERT(pdf->getPageCount()==currPageCount); getNodePosition(*pdf, firstPage->getDictionary(), NULL); } // checks PageTreeRootObserver for all possible situations: Pages // property (add, delete or change and Pages reference change) printf("TC10:\tremoving page tree root test\n"); shared_ptr pageTreeRoot=getPageTreeRoot(*pdf); size_t currPageCount=pdf->getPageCount(); pdf->getDictionary()->delProperty("Pages"); CPPUNIT_ASSERT(pdf->getPageCount()==0); printf("TC11:\tadding wrong page tree root element\n"); shared_ptr fakeInterCRef(CRefFactory::getInstance(fakeInterRef)); pdf->getDictionary()->addProperty("Pages", *fakeInterCRef); CPPUNIT_ASSERT(pdf->getPageCount()==0); try { pdf->getFirstPage(); CPPUNIT_FAIL("getFirstPage should have failed on empty page tree."); }catch(PageNotFoundException & e) { /* ok */ } try { pdf->getLastPage(); CPPUNIT_FAIL("getLastPage should have failed on empty page tree."); }catch(PageNotFoundException & e) { /* ok */ } printf("TC12:\treplacing page tree root test\n"); // creates new reference which points to some nonsense and changes Pages // reference value shared_ptr pagesProp=IProperty::getSmartCObjectPtr(pdf->getDictionary()->getProperty("Pages")); pagesProp->setValue(pdf->addIndirectProperty(shared_ptr(CIntFactory::getInstance(1)))); CPPUNIT_ASSERT(pdf->getPageCount()==0); // sets new Pages property with correct reference to page tree root // (original one) scoped_ptr pageTreeRootCRef(CRefFactory::getInstance(pageTreeRoot->getIndiRef())); pdf->getDictionary()->setProperty("Pages", *pageTreeRootCRef); CPPUNIT_ASSERT(pdf->getPageCount()==currPageCount); // change made to document CPPUNIT_ASSERT(pdf->isChanged()); } /** Multiversion file name. */ #define MV_F "tests/multiversion.pdf" /** Multiversion revisin count. */ #define MV_RC 4 #define TRY_READONLY_OP(method, errorMsg)\ {\ try\ {\ method;\ CPPUNIT_FAIL(errorMsg);\ }catch(ReadOnlyDocumentException &e)\ {\ /* passed */\ }\ } void revisionsTC() { using namespace boost; printf("%s\n", __FUNCTION__); // opens special test file printf("Using file \"%s\"\n", MV_F); CPdf *pdf=getTestCPdf(MV_F); CPdf::OpenMode mode=pdf->getMode(); // number of revision must match printf("TC01:\tRevisions count test\n"); CPPUNIT_ASSERT(pdf->getRevisionsCount()==MV_RC); printf("TC02:\tchangeRevision, getActualRevision tests\n"); for(CPdf::revision_t i=0; igetRevisionsCount(); i++) { pdf->changeRevision(i); CPPUNIT_ASSERT(pdf->getActualRevision()==i); } printf("TC03:\tgetPageCount for revision test\n"); // starts from the oldest one - each revision has number of pages one // more than revision number for(CPdf::revision_t i=pdf->getRevisionsCount()-1; ; i--) { pdf->changeRevision(i); CPPUNIT_ASSERT(pdf->getPageCount()==i+1); if(i==0) break; } printf("TC04:\tgetCXref::getNumObjects is same for all revisions\n"); // no changes has been done, so all revisions has to have same number // of objects int number=0; for(CPdf::revision_t i=0; igetPageCount(); i++) { pdf->changeRevision(i); if(!number) { // first information is just stored to number number=pdf->getCXref()->getNumObjects(); continue; } CPPUNIT_ASSERT(pdf->getCXref()->getNumObjects()==number); } printf("TC05:\tolder revisions has to be readOnly\n"); for(CPdf::revision_t i=1; igetRevisionsCount(); i++) { pdf->changeRevision(i); CPPUNIT_ASSERT(pdf->getMode()==CPdf::ReadOnly); } printf("TC06:\tThe newest revision has mode same as set in getInstace\n"); pdf->changeRevision(0); CPPUNIT_ASSERT(pdf->getMode()==mode); printf("TC07:\tno changes can be done in older revisions\n"); for(CPdf::revision_t i=1; igetRevisionsCount(); i++) { printf("\trevision=%d\n", i); pdf->changeRevision(i); // addIndirectProperty printf("\t\taddIndirectProperty\n"); shared_ptr prop(CIntFactory::getInstance(1)); TRY_READONLY_OP(pdf->addIndirectProperty(prop),"addIndirectProperty should have failed"); // changeIndirectProperty printf("\t\tchangeIndirectProperty\n"); TRY_READONLY_OP(pdf->changeIndirectProperty(prop),"changeIndirectProperty should have failed"); // insertPage shared_ptr pageDict(CDictFactory::getInstance()); shared_ptr page(CPageFactory::getInstance(pageDict)); printf("\t\tinsertPage\n"); TRY_READONLY_OP(pdf->insertPage(page,1), "insertPage should have failed"); // removePage printf("\t\tremovePage\n"); TRY_READONLY_OP(pdf->removePage(1), "removePage should have failed"); } // isModified returns always false printf("TC08:\tisChanged is allways false on unchanged document\n"); CPPUNIT_ASSERT(!pdf->isChanged()); pdf->close(); } #undef TRY_READONLY_OP void instancingTC() { printf("%s\n", __FUNCTION__); // checks whether getInstance works correctly // TODO figure out } void indirectPropertyTC(CPdf * pdf) { using namespace boost; using namespace utils; printf("%s\n", __FUNCTION__); printf("TC01:\taddIndirectProperty with simple property with no pdf\n"); // creates new property and adds it shared_ptr prop(CIntFactory::getInstance(1)); IndiRef addedRef,intPropRef; addedRef=intPropRef=pdf->addIndirectProperty(prop); CPPUNIT_ASSERT(addedRef.num!=0); shared_ptr added=pdf->getIndirectProperty(addedRef); // type must be same CPPUNIT_ASSERT(added->getType()==prop->getType()); // value must be same (we know that prop is CInt) PropertyEquals pe; CPPUNIT_ASSERT(pe(added, prop)); CPPUNIT_ASSERT(added->getPdf()==pdf); CPPUNIT_ASSERT(added->getIndiRef()==addedRef); printf("\t\tReference state is INITIALIZED_REF (according CXref::knowsRef)\n"); CPPUNIT_ASSERT(pdf->getCXref()->knowsRef(addedRef)==INITIALIZED_REF); printf("TC02:\taddIndirectProperty with reference with no pdf\n"); IndiRef ref(1,0); shared_ptr refProp(CRefFactory::getInstance(ref)); try { addedRef=pdf->addIndirectProperty(refProp); CPPUNIT_FAIL("addIndirectProperty with reference should have failed"); }catch(ElementBadTypeException & e) { /* ok, should have failed */ } printf("TC03:\taddIndirectProperty dictionary with no pdf\n"); // prepares dictionary with 3 entries // Elem1 Real // Elem2 Ref // Elem3 [Bool] shared_ptr dictProp(CDictFactory::getInstance()); shared_ptr dictElem1(CRealFactory::getInstance(1.5)); dictProp->addProperty("Elem1", *dictElem1); shared_ptr dictElem2(CRefFactory::getInstance(ref)); dictProp->addProperty("Elem2", *dictElem2); shared_ptr dictElem3(new CArray()); shared_ptr arrayElem1(CBoolFactory::getInstance(true)); dictElem3->addProperty(*arrayElem1); dictProp->addProperty("Elem3", *dictElem3); // adds dictionary addedRef=pdf->addIndirectProperty(dictProp); added=pdf->getIndirectProperty(addedRef); CPPUNIT_ASSERT(isDict(*added)); shared_ptr addedDict=IProperty::getSmartCObjectPtr(added); CPPUNIT_ASSERT(added->getPdf()==pdf); CPPUNIT_ASSERT(added->getIndiRef()==addedRef); CPPUNIT_ASSERT(addedDict->getPropertyCount()==3); CPPUNIT_ASSERT(isReal(*(addedDict->getProperty("Elem1")))); CPPUNIT_ASSERT(isRef(*(addedDict->getProperty("Elem2")))); // target of Elem2 has to be CNull CPPUNIT_ASSERT( isNull( * pdf->getIndirectProperty( getValueFromSimple(addedDict->getProperty("Elem2")) ) ) ); CPPUNIT_ASSERT(isArray(*(addedDict->getProperty("Elem3")))); printf("TC04:\taddIndirectProperty with CRef from same pdf\n"); // uses root of page tree, which has to be reference shared_ptr rootProp=pdf->getDictionary()->getProperty("Pages"); if(isRef(rootProp)) { shared_ptr rootCRef=IProperty::getSmartCObjectPtr(rootProp); try { addedRef=pdf->addIndirectProperty(rootCRef); CPPUNIT_FAIL("addIndirectProperty with reference should have failed"); }catch(ElementBadTypeException & e) { /* ok should have failed */ } } printf("TC05:\taddIndirectProperty from different pdf (followRefs==false)\n"); // opens TEST_FILE CPdf * differentPdf=getTestCPdf(TEST_FILE); // gets page dictionary which contains at least one reference (to its // parent). addIndirectProperty with followRefs==false shared_ptr differentPageDict=differentPdf->getFirstPage()->getDictionary(); addedRef=pdf->addIndirectProperty(differentPageDict, false); added=pdf->getIndirectProperty(addedRef); CPPUNIT_ASSERT(added->getIndiRef()==addedRef); CPPUNIT_ASSERT(added->getPdf()==pdf); CPPUNIT_ASSERT(isDict(*added)); printf("\t\tReference state is INITIALIZED_REF (according CXref::knowsRef)\n"); CPPUNIT_ASSERT(pdf->getCXref()->knowsRef(addedRef)==INITIALIZED_REF); addedDict=IProperty::getSmartCObjectPtr(added); CPPUNIT_ASSERT(addedDict->getPropertyCount()==differentPageDict->getPropertyCount()); // gets parent dictionary and checks if its reference is known and value // is CNull (because deep copy was not done) shared_ptr parentProp=addedDict->getProperty("Parent"); if(isRef(*parentProp)) { ref=getValueFromSimple(parentProp); shared_ptr parentPropValue=pdf->getIndirectProperty(ref); CPPUNIT_ASSERT(isNull(*parentPropValue)); ::Ref xpdfRef={ref.num, ref.gen}; // has to know reference as RESERVED_REF printf("\t\tReference state of parentProp is RESERVED_REF (according CXref::knowsRef)\n"); CPPUNIT_ASSERT(pdf->getCXref()->knowsRef(xpdfRef)==RESERVED_REF); } printf("TC06:\taddIndirectProperty from different pdf (followRefs==true)\n"); // does the same as for tc05 with followRefs set to true and "Parent" // property from differentPageDict - insertion should reuse mapping from // firts insetion - without followRefs parentProp=differentPageDict->getProperty("Parent"); IndiRef parentRef=getValueFromSimple(parentProp); shared_ptr differentPageProp=differentPdf->getIndirectProperty(parentRef); CPPUNIT_ASSERT(isDict(*differentPageProp)); differentPageDict=IProperty::getSmartCObjectPtr(differentPageProp); addedRef=pdf->addIndirectProperty(differentPageDict, true); // addededRef must be same as reserved in first insertion CPPUNIT_ASSERT(addedRef==ref); added=pdf->getIndirectProperty(addedRef); CPPUNIT_ASSERT(added->getIndiRef()==addedRef); CPPUNIT_ASSERT(added->getPdf()==pdf); CPPUNIT_ASSERT(isDict(*added)); printf("\t\tReference state is INITIALIZED_REF (according CXref::knowsRef)\n"); CPPUNIT_ASSERT(pdf->getCXref()->knowsRef(addedRef)==INITIALIZED_REF); addedDict=IProperty::getSmartCObjectPtr(added); CPPUNIT_ASSERT(addedDict->getPropertyCount()==differentPageDict->getPropertyCount()); differentPdf->close(); printf("TC07:\tgetIndirectProperty with uknown reference returns CNull\n"); // creates unknown reference from existing by adding 1 to generation // number IndiRef unknownRef=pdf->getDictionary()->getIndiRef(); unknownRef.gen++; CPPUNIT_ASSERT(isNull(*pdf->getIndirectProperty(unknownRef))); printf("\t\tReference state is UNUSED_REF (according CXref::knowsRef)\n"); CPPUNIT_ASSERT(pdf->getCXref()->knowsRef(unknownRef)==UNUSED_REF); printf("TC08:\tchangeIndirectProperty with invalid parameter should fail\n"); // creates fake and try to use changeIndirectProperty with unknownRef Object obj; obj.initInt(1); shared_ptr fakeInt(CIntFactory::getInstance(*pdf, unknownRef, obj)); try { pdf->changeIndirectProperty(fakeInt); CPPUNIT_FAIL("changeIndirectProperty should have failed with faked object"); }catch(CObjInvalidObject & e) { /* ok */ } printf("TC09:\tchangeIndirectProperty with bad typed parameter should fail\n"); // creates integer and tries to change value of Pages field which is // reference fakeInt=shared_ptr(CIntFactory::getInstance(*pdf, pdf->getDictionary()->getProperty("Pages")->getIndiRef(), obj)); try { pdf->changeIndirectProperty(fakeInt); CPPUNIT_FAIL("changeIndirectProperty with bad typed value should have failed"); }catch(ElementBadTypeException & e) { /* ok */ } printf("TC08:\tChanging indirect property causes CPdf::changeIndirectProperty\n"); // changes intPropRef added at the method beginning shared_ptr originalIntProp=IProperty::getSmartCObjectPtr(pdf->getIndirectProperty(intPropRef)); // in first case change value directly in originalIntProp int originalIntValue=getIntFromIProperty(originalIntProp); // this should automatically call pdf->changeIndirectProperty originalIntProp->setValue(originalIntValue+1); shared_ptr changedIntProp=IProperty::getSmartCObjectPtr(pdf->getIndirectProperty(intPropRef)); // we have changed just value, so instance must be same CPPUNIT_ASSERT(changedIntProp==originalIntProp); CPPUNIT_ASSERT(getIntFromIProperty(changedIntProp)-1==originalIntValue); printf("TC09:\tchangeIndirectProperty with proper (different) value\n"); // sets changed property as original now and resets changedIntProp with // new value - so we have different instance of property with same type, // so type check doesn't fail originalIntProp=changedIntProp; changedIntProp.reset(); Object intXpdfObj; intXpdfObj.initInt(0); changedIntProp=shared_ptr(CIntFactory::getInstance(*pdf, intPropRef, intXpdfObj)); pdf->changeIndirectProperty(changedIntProp); // resets value and gets it again changedIntProp.reset(); changedIntProp=IProperty::getSmartCObjectPtr(pdf->getIndirectProperty(intPropRef)); // instances must be different CPPUNIT_ASSERT(changedIntProp!=originalIntProp); CPPUNIT_ASSERT(getIntFromIProperty(changedIntProp)==0); // reference is kept CPPUNIT_ASSERT(changedIntProp->getIndiRef()==originalIntProp->getIndiRef()); } void delinearizatorTC(string fileName) { using namespace pdfobjects::utils; printf("%s\n", __FUNCTION__); // creates delinearizator and delinearize file to the file // fileName-delinearized.pdf IPdfWriter * writer=new OldStylePdfWriter(); ProgressBar * progressBar=new ProgressBar(cout); writer->registerObserver(shared_ptr(new ProgressObserver(progressBar))); Delinearizator *delinearizator=Delinearizator::getInstance(fileName.c_str(), writer); if(!delinearizator) { printf("\t%s is not suitable because it is not linearized.\n", fileName.c_str()); return; } string outputFile=fileName+"-delinearizator.pdf"; printf("\tDelinearized output is in %s file\n", outputFile.c_str()); delinearizator->delinearize(outputFile.c_str()); delete delinearizator; } void setUp() { } void tearDown() { } void Test() { instancingTC(); // creates pdf instances for all files for(FileList::iterator i=fileList.begin(); i!=fileList.end(); i++) { string fileName=*i; printf("\nTests for file:%s\n", fileName.c_str()); CPdf * pdf=getTestCPdf(fileName.c_str()); string filterName; if(pdfobjects::utils::isEncrypted(*pdf, &filterName)) { printf("Test file is encrypted and so not supported.\n"); printf("File is encrypted by %s method\n", filterName.c_str()); continue; } // pageIterationTC is before indirectPropertyTC because it needs to // have no changes made before (checks isChanged on non change // producing operations) pageIterationTC(pdf); cloneTC(pdf, fileName); indirectPropertyTC(pdf); pageManipulationTC(pdf); pdf->close(); delinearizatorTC(fileName); } revisionsTC(); printf("TEST_CPDF testig finished\n"); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestCPdf); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestCPdf, "TEST_CPDF"); pdfobjects::CPdf * getTestCPdf(const char* filename) { return CPdf::getInstance(filename, CPdf::ReadWrite); }