“Actions” make PDF documents interactive and more complex. “Complex” means that they should be tested, especially when interactive documents are part of a workflow.
An “action” is a dictionary object inside PDF containing the keys
/S and /Type.
The key /Type always maps to the value “Action”.
And the the key /S (Subtype) has different values:
// Types of actions: GoTo: Set the focus to a destination in the current PDF document GoToR: Set the focus to a destination in another PDF document GoToE: Go to a destination inside an embedded file GoTo3DView: Set the view to a 3D annotation Hide: Set the hidden flag of the specified annotation ImportData: Import data from a file to the current document JavaScript: Execute JavaScript code Movie: Play a specified movie Named: Execute an action, which is predefined by the PDF viewer Rendition: Control the playing of multimedia content ResetForm: Set the values of form fields to default SetOCGState: Set the state of an OCG Sound: Play a specified sound SubmitForm: Send the form data to an URL Launch: Execute an application Thread: Set the viewer to the beginning of a specified article Trans: Update the display of a document, using a transition dictionary URI: Go to the remote URI
For a few of these actions PDFUnit provides test methods. Future releases will have more tests methods.
// Simple tests: .hasNumberOfActions(..) // Action specific tests: .hasJavaScriptAction() .hasJavaScriptAction().containing(..) .hasJavaScriptAction().containingSource(..) .hasJavaScriptAction().equalsTo(..) .hasJavaScriptAction().equalsToSource(..) .hasJavaScriptAction().matchingRegex(..) .hasLocalGotoAction() .hasLocalGotoAction().toDestination(..) .hasLocalGotoAction().toDestination(.., pageNumber)
The following sections show examples for these test methods.
Since JavaScript code is generally quite long, it makes sense to read the expected text for a JavaScript-Action test from a file:
@Test public void hasJavaScriptAction_WithWhitespaceProcessing() throws Exception { String filename = "documentUnderTest.pdf"; String scriptFileName = "javascript/javascriptAction_OneSimpleAlert.js"; Reader scriptFileAsReader = new FileReader(scriptFileName); AssertThat.document(filename) .hasJavaScriptAction() .equalsToSource(scriptFileAsReader, WhitespaceProcessing.IGNORE) ; }
The parameter of the method equalsToSource(..) (and also containingSource(..))
can be of type java.io.Reader, java.io.InputStream
or java.lang.String.
The content of the JavaScript file is completely compared with the content of the JavaScript action. White spaces are ignored.
But parts of a JavaScript code can be checked as well:
@Test public void hasJavaScript_ContainingText_FunctionNames() throws Exception { String filename = "javaScriptClock.pdf"; AssertThat.document(filename) .hasJavaScript() .containing("StopWatchProc") .containing("SetFldEnable") .containing("DoTimers") .containing("ClockProc") .containing("CountDownProc") .containing("CDEnables") .containing("SWSetEnables") ; }
Chapter 13.5: “Whitespace Processing” explains the flexible handling of whitespaces.
Goto-Actions need a destination in the same PDF document:
@Test public void hasGotoAction_ToNamedDestination() throws Exception { String filename = "documentUnderTest.pdf"; String destinationName21 = "destination2.1"; AssertThat.document(filename) .hasLocalGotoAction() .toDestination(destinationName21) ; }
This test is successful if the tested PDF contains the expected destination “destination2.1”. Chapter 4.11: “Comparing Named Destinations” discusses how to test destinations together with bookmarks.
It is also possible to check whether a destination is located on a given page:
@Test public void hasGotoAction_ToDestinationWithPage_Page3() throws Exception { String filename = "documentUnderTest.pdf"; String destinationName21 = "destination2.1"; int page3 = 3; AssertThat.document(filename) .hasLocalGotoAction() .toDestination(destinationName21, page3) ; }