[app] Add totals to 'balance sheet' (bug #26)
[abstract.git] / cxxunit / nsTestRunner.cpp
blobb66e0ade5d0c864765f5c3f16bc932cb7c4acd7a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent tw=79 ft=cpp: */
3 /*
4 * Copyright (C) 2007 Sergey Yanovich <ynvich@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <abstract/aacore.h>
24 #include "nsXPCOM.h"
25 #include "nsStringAPI.h"
26 #include "nsEmbedString.h"
27 #include "nsWeakReference.h"
28 #include "nsIWebProgressListener.h"
29 #include "nsIComponentManager.h"
30 #include "nsComponentManagerUtils.h"
31 #include "nsServiceManagerUtils.h"
32 #include "nsIPrefBranch.h"
33 #include "nsIWindowWatcher.h"
34 #include "nsIDOMWindow.h"
35 #include "nsIInterfaceRequestorUtils.h"
36 #include "nsIWebProgress.h"
37 #include "nsIDOMDocument.h"
38 #include "nsIDOMElement.h"
39 #include "nsIDOMEventTarget.h"
40 #include "nsIDOMDocumentEvent.h"
41 #include "nsIDOMEvent.h"
42 #include "nsIDOMAbstractView.h"
44 /* Unfrozen interfaces */
45 #include "unstable/nsITimer.h"
46 #include "unstable/nsICommandLineHandler.h"
47 #include "unstable/nsDeque.h"
48 #include "unstable/nsAutoPtr.h"
49 #include "unstable/nsICommandLine.h"
50 #include "unstable/nsIWebNavigation.h"
51 #include "unstable/nsIAppStartup.h"
52 #include "unstable/nsIConsoleListener.h"
53 #include "unstable/nsIConsoleService.h"
54 #include "unstable/nsIConsoleMessage.h"
55 #include "unstable/nsIScriptError.h"
56 #include "unstable/jspubtd.h"
57 #include "unstable/nsIJSContextStack.h"
58 #include "unstable/nsIRDFService.h"
59 #include "unstable/nsIRDFDataSource.h"
60 #include "unstable/nsIRDFResource.h"
61 #include "unstable/nsIDOMXULDocument.h"
62 #include "unstable/nsIDOMXULCommandDispatcher.h"
63 #include "unstable/nsIDOMXULCommandEvent.h"
64 #include "unstable/nsIStringEnumerator.h"
66 /* Project includes */
67 #include <abstract/cxxunit/nsITestRunner.h>
68 #include <abstract/cxxunit/nsITestResult.h>
69 #include <abstract/cxxunit/nsITest.h>
70 #include "nstestjs.h"
71 #include "nsTestRunner.h"
72 #include "nsTestFailure.h"
74 #include <abstract/cxxunit/nsTestUtils.h>
76 class nsFormatJSMessage: public nsTestFailure
78 public:
79 nsFormatJSMessage(nsIConsoleMessage *aMessage);
80 nsFormatJSMessage(const char *aFile);
81 ~nsFormatJSMessage() {;}
82 private:
83 nsresult parseScriptError(nsIConsoleMessage *aMessage);
84 nsresult formatErrorMessage(nsIScriptError *error);
85 PRBool parseException(const nsACString &aMessage);
86 nsresult getSourceFile();
87 nsresult parseLocalFile();
88 nsresult parseChrome();
90 PRBool mIsChrome;
91 nsRefPtr<nsTestRunner> mResolver;
95 /******************** nsTestRunner ***********************************/
96 nsTestRunner* nsTestRunner::gTestRunner = nsnull;
98 nsTestRunner::nsTestRunner() : mTestTree(nsnull)
100 mArmed = PR_FALSE;
101 mRunning = PR_FALSE;
104 nsTestRunner::~nsTestRunner()
108 NS_IMPL_THREADSAFE_ISUPPORTS6(nsTestRunner,
109 nsITestRunner,
110 nsIConsoleListener,
111 nsIWebProgressListener,
112 nsISupportsWeakReference,
113 nsITimerCallback,
114 nsICommandLineHandler);
116 NS_IMETHODIMP
117 nsTestRunner::MarkTestStart()
119 return mTestResult->MarkTestStart();
122 NS_IMETHODIMP
123 nsTestRunner::AddFailure(const char *aFile, PRUint32 aLine, const char *aText)
125 return mTestResult->AddFailure(aFile, aLine, aText, PR_FALSE);
128 NS_IMETHODIMP
129 nsTestRunner::AddJSFailure(const char *aText)
131 nsresult rv;
132 JSContext *cx = nsnull;
133 nsEmbedCString file;
135 if ( ! mJSStack ) {
136 mJSStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
137 NS_ENSURE_TRUE(mJSStack, NS_ERROR_FAILURE);
139 rv = mJSStack->Peek( &cx );
140 NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
142 nsFormatJSMessage m(ns_test_js_caller_filename(cx));
144 return mTestResult->AddFailure(m.getFile(),
145 ns_test_js_caller_lineno(cx) + 1, aText, PR_FALSE);
148 NS_IMETHODIMP
149 nsTestRunner::AddError(PRUint32 aCode, const char *aComment)
151 return mTestResult->AddFailure(nsnull, aCode, aComment, PR_TRUE);
154 NS_IMETHODIMP
155 nsTestRunner::MarkTestEnd(nsITest *aTest)
157 if (aTest != (nsITest *) mTestTree.Peek())
158 return NS_ERROR_ILLEGAL_VALUE;
159 if (mArmed) {
160 mArmed = PR_FALSE;
161 mTimerStop->Cancel();
162 if(NS_FAILED(mTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)))
163 traverse();
165 return NS_OK;
168 NS_IMETHODIMP
169 nsTestRunner::GetTestWindow(nsIDOMWindow* *aTestWindow)
171 NS_ENSURE_ARG_POINTER( aTestWindow );
172 if ( !mTestWindow ) {
173 *aTestWindow = nsnull;
174 return NS_ERROR_NOT_INITIALIZED;
176 *aTestWindow = mTestWindow;
177 NS_ADDREF( *aTestWindow );
179 return NS_OK;
182 NS_IMETHODIMP
183 nsTestRunner::GetWatchWindow(nsIDOMWindow* *aWatchWindow)
185 NS_ENSURE_ARG_POINTER( aWatchWindow );
186 if ( !mWatchWindow ) {
187 *aWatchWindow = nsnull;
188 return NS_ERROR_NOT_INITIALIZED;
190 *aWatchWindow = mWatchWindow;
191 NS_ADDREF( *aWatchWindow );
193 return NS_OK;
196 NS_IMETHODIMP
197 nsTestRunner::SetWatchWindow(nsIDOMWindow *aWatchWindow)
199 nsresult rv;
201 if (mWatchWindow) {
202 nsCOMPtr<nsIWebNavigation> web(do_GetInterface(mWatchWindow, &rv ));
203 NS_ENSURE_SUCCESS(rv, rv);
205 nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(web, &rv));
206 NS_ENSURE_SUCCESS(rv, rv);
208 rv = webProgress->RemoveProgressListener(this);
209 NS_ENSURE_SUCCESS(rv, rv);
212 if (aWatchWindow) {
213 nsCOMPtr<nsIWebNavigation> web(do_GetInterface(aWatchWindow, &rv ));
214 NS_ENSURE_SUCCESS(rv, rv);
216 nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(web, &rv));
217 NS_ENSURE_SUCCESS(rv, rv);
219 rv = webProgress->AddProgressListener(this,
220 nsIWebProgress::NOTIFY_STATE_WINDOW);
221 NS_ENSURE_SUCCESS(rv, rv);
223 mWatchWindow = aWatchWindow;
225 return NS_OK;
228 NS_IMETHODIMP
229 nsTestRunner::ArmTimer()
231 nsresult rv;
232 nsITest *test = (nsITest *) mTestTree.Peek();
234 nsCOMPtr<nsITimerCallback> callback(do_QueryInterface(test, &rv));
235 NS_ENSURE_SUCCESS(rv, rv);
236 rv = mTimer->InitWithCallback(callback, 0, nsITimer::TYPE_ONE_SHOT);
237 NS_ENSURE_SUCCESS(rv, rv);
238 if (! mArmed )
239 mRunning = PR_TRUE;
240 return NS_OK;
243 NS_IMETHODIMP
244 nsTestRunner::DoCommand(const nsAString& aCommand)
246 nsresult rv;
247 nsCOMPtr<nsIDOMWindow> wnd(mTestWindow);
248 nsIDOMWindow *next;
249 nsCOMPtr<nsIDOMDocument> doc;
250 nsCOMPtr<nsIDOMXULDocument> xulDoc;
251 nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher;
252 nsCOMPtr<nsIDOMElement> element;
254 while ( wnd ) {
255 rv = wnd->GetDocument(getter_AddRefs( doc ));
256 NS_ENSURE_SUCCESS(rv, rv);
258 rv = doc->GetElementById(aCommand, getter_AddRefs( element ));
259 if ( element )
260 break;
262 xulDoc = do_QueryInterface(doc, &rv);
263 NS_ENSURE_SUCCESS(rv, NS_ERROR_ILLEGAL_VALUE);
265 rv = xulDoc->GetCommandDispatcher(getter_AddRefs( dispatcher ));
266 NS_ENSURE_SUCCESS(rv, rv);
268 rv = dispatcher->GetFocusedWindow( &next );
269 NS_ENSURE_SUCCESS(rv, rv);
271 if ( wnd == next ) {
272 wnd = nsnull;
273 } else {
274 wnd = getter_AddRefs( next );
278 NS_ENSURE_TRUE(element, NS_ERROR_ILLEGAL_VALUE);
280 PRBool isDisabled;
281 rv = element->HasAttribute(NS_LITERAL_STRING("disabled"), &isDisabled);
282 NS_ENSURE_SUCCESS(rv, rv);
283 if ( isDisabled )
284 return NS_ERROR_NOT_AVAILABLE;
286 nsCOMPtr<nsIDOMEventTarget> evtTgt(do_QueryInterface(element, &rv));
287 NS_ENSURE_SUCCESS(rv, rv);
289 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(doc, &rv));
290 NS_ENSURE_SUCCESS(rv, rv);
292 nsCOMPtr<nsIDOMEvent> evt;
293 rv = docEvent->CreateEvent(NS_LITERAL_STRING("XULCommandEvent"),
294 getter_AddRefs(evt));
295 NS_ENSURE_SUCCESS(rv, rv);
297 nsCOMPtr<nsIDOMXULCommandEvent> cmdEvt(do_QueryInterface(evt, &rv));
298 NS_ENSURE_SUCCESS(rv, rv);
300 nsCOMPtr<nsIDOMAbstractView> view(do_QueryInterface(wnd, &rv));
301 NS_ENSURE_SUCCESS(rv, rv);
303 rv = cmdEvt->InitCommandEvent(NS_LITERAL_STRING("command"), PR_TRUE, PR_TRUE,
304 view, 0, 0, 0, 0, 0, nsnull);
305 NS_ENSURE_SUCCESS(rv, rv);
307 PRBool isDefault;
308 rv = evtTgt->DispatchEvent( evt, &isDefault );
309 NS_ENSURE_SUCCESS(rv, rv);
311 return NS_OK;
314 NS_IMETHODIMP
315 nsTestRunner::Observe(nsIConsoleMessage *aMessage)
317 NS_ENSURE_TRUE(mTestResult, NS_ERROR_UNEXPECTED);
319 nsFormatJSMessage m(aMessage);
320 mTestResult->AddFailure(m.getFile(), m.getLine(), m.getText(), PR_TRUE);
321 return NS_OK;
324 nsresult
325 nsTestRunner::openMainWindow()
327 nsresult rv;
328 nsCOMPtr<nsIConsoleService> jsConsole;
329 nsCOMPtr<nsIPrefBranch> pref;
330 nsEmbedCString chromeURI;
331 nsCOMPtr<nsIWindowWatcher> ww;
332 nsCOMPtr<nsIDOMWindow> wnd;
334 pref = do_GetService("@mozilla.org/preferences-service;1", &rv);
335 NS_ENSURE_SUCCESS(rv, rv);
336 rv = pref->GetCharPref("toolkit.defaultChromeURI",getter_Copies(chromeURI));
337 NS_ENSURE_SUCCESS(rv, rv);
338 ww = do_GetService("@mozilla.org/embedcomp/window-watcher;1", &rv);
339 NS_ENSURE_SUCCESS(rv, rv);
340 rv = ww->OpenWindow(0, chromeURI.get(), "_blank", "chrome,dialog=no,all",
341 0, getter_AddRefs(wnd) );
342 NS_ENSURE_SUCCESS(rv, rv);
344 mTestWindow = wnd;
345 jsConsole = do_GetService("@mozilla.org/consoleservice;1", &rv);
346 NS_ENSURE_TRUE(jsConsole, NS_OK);
347 jsConsole->RegisterListener( this );
349 return NS_OK;
352 void
353 nsTestRunner::run()
355 if ( init() != NS_ERROR_ABORT)
356 traverse();
359 nsresult
360 nsTestRunner::init()
362 nsresult rv;
363 nsCOMPtr<nsIPrefBranch> pref;
365 pref = do_GetService("@mozilla.org/preferences-service;1", &rv);
366 NS_ENSURE_SUCCESS(rv, rv);
367 rv = pref->GetCharPref("cxxunit.firstTest",getter_Copies(mTestID));
368 NS_ENSURE_SUCCESS(rv, rv);
370 rv = pushTest( mTestID.get() );
371 NS_ENSURE_SUCCESS(rv, rv);
373 return runCurrentTest();
376 nsresult
377 nsTestRunner::pushTest(const char * aContractID)
379 nsresult rv;
380 void *test;
381 nsCOMPtr<nsIComponentManager> componentManager;
383 rv = NS_GetComponentManager(getter_AddRefs( componentManager ));
384 NS_ENSURE_SUCCESS(rv, rv);
385 rv = componentManager->CreateInstanceByContractID(aContractID, nsnull,
386 NS_GET_IID(nsITest), (void **) &test);
387 if (NS_FAILED(rv)) {
388 AddError(nsITestRunner::errorLoad, aContractID);
389 return rv;
392 mTestTree.Push( (void *) test );
393 return NS_OK;
396 nsresult
397 nsTestRunner::runCurrentTest()
399 nsITest *test = (nsITest *) mTestTree.Peek();
401 test->Test( this );
402 if ( mRunning || mWatchWindow ) {
403 mRunning = PR_FALSE;
404 mArmed = PR_TRUE;
405 mTimerStop->InitWithCallback(this, 1000, nsITimer::TYPE_ONE_SHOT);
406 return NS_ERROR_ABORT;
409 return NS_OK;
412 nsresult
413 nsTestRunner::getNextTest(nsACString &aContractID)
415 nsresult rv;
416 PRBool hasMore;
418 nsITest *test = (nsITest *) mTestTree.Peek();
419 NS_ENSURE_TRUE(test, NS_ERROR_UNEXPECTED);
421 nsCOMPtr<nsIUTF8StringEnumerator> testNode(do_QueryInterface(test, &rv));
422 if (rv == NS_NOINTERFACE)
423 return NS_ERROR_NOT_AVAILABLE;
424 NS_ENSURE_SUCCESS(rv, rv);
426 rv = testNode->HasMore( &hasMore );
427 NS_ENSURE_SUCCESS(rv, rv);
428 if (! hasMore)
429 return NS_ERROR_NOT_AVAILABLE;
431 rv = testNode->GetNext( aContractID );
432 NS_ENSURE_SUCCESS(rv, rv);
434 return NS_OK;
437 void
438 nsTestRunner::traverse()
440 nsresult rv;
441 nsEmbedCString nextContractID(0);
442 nsITest *test;
444 while (mTestTree.GetSize()) {
446 rv = getNextTest( mTestID );
448 if (NS_FAILED(rv)) {
449 test = (nsITest *) mTestTree.Pop();
450 NS_RELEASE(test);
451 } else {
452 if (NS_FAILED( pushTest( mTestID.get() ) ))
453 continue;
454 if (NS_FAILED( runCurrentTest() ))
455 return;
459 if (NS_FAILED( mTimer->InitWithFuncCallback(done, this, 0,
460 nsITimer::TYPE_ONE_SHOT) )) {
461 done(nsnull, this);
465 nsresult
466 nsTestRunner::closeMainWindow()
468 nsresult rv;
469 nsCOMPtr<nsIAppStartup> app;
470 app = do_GetService("@mozilla.org/toolkit/app-startup;1", &rv);
471 NS_ENSURE_SUCCESS(rv, rv);
472 rv = app->Quit(app->eForceQuit);
473 NS_ENSURE_SUCCESS(rv, rv);
474 return NS_OK;
477 void
478 nsTestRunner::done(nsITimer *aTimer, void *aClosure)
480 nsTestRunner *self = static_cast<nsTestRunner*>(aClosure);
481 nsCOMPtr<nsIConsoleService> jsConsole;
483 jsConsole = do_GetService("@mozilla.org/consoleservice;1");
484 if (jsConsole )
485 jsConsole->UnregisterListener( self );
487 self->closeMainWindow();
488 self->mTestResult->Done();
489 self->mTestResult = nsnull;
490 self->mTimer = nsnull;
493 NS_IMETHODIMP
494 nsTestRunner::Handle(nsICommandLine *aCommandLine)
496 nsresult rv;
497 PRBool isTest;
499 rv = aCommandLine->HandleFlag(NS_LITERAL_STRING("test"), PR_TRUE, &isTest);
500 NS_ENSURE_SUCCESS(rv,rv);
501 if (isTest){
502 aCommandLine->SetPreventDefault(PR_TRUE);
504 mTimer = do_CreateInstance("@mozilla.org/timer;1");
505 NS_ENSURE_TRUE(mTimer, NS_ERROR_ABORT);
507 mTimerStop = do_CreateInstance("@mozilla.org/timer;1");
508 NS_ENSURE_TRUE(mTimer, NS_ERROR_ABORT);
510 mTestResult = do_CreateInstance("@aasii.org/cxxunit/testresult", &rv);
511 NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
513 if (NS_FAILED( openMainWindow() )) {
514 rv = NS_ERROR_ABORT;
516 run();
517 return rv;
519 return NS_OK;
522 NS_IMETHODIMP
523 nsTestRunner::GetHelpInfo(nsACString & aHelpInfo)
525 aHelpInfo.Assign(" --test Run unit test collection\n");
526 return NS_OK;
529 nsresult
530 nsTestRunner::resolve(nsACString &aURL, const PRUnichar* *result)
532 nsresult rv;
533 nsCOMPtr<nsIRDFService> rdfSrv;
534 nsCOMPtr<nsIRDFResource> src, prop;
535 nsCOMPtr<nsIRDFNode> target;
536 nsCOMPtr<nsIRDFLiteral> targetLiteral;
538 NS_ENSURE_ARG_POINTER(result);
539 *result = nsnull;
540 rdfSrv = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
541 NS_ENSURE_SUCCESS( rv, rv );
543 if ( ! mFileMap ) {
544 nsCOMPtr<nsIPrefBranch> pref;
545 nsEmbedCString url;
547 pref = do_GetService("@mozilla.org/preferences-service;1", &rv);
548 NS_ENSURE_SUCCESS(rv, rv );
549 rv = pref->GetCharPref("cxxunit.fileMap",getter_Copies(url));
550 NS_ENSURE_SUCCESS(rv, rv );
552 rv = rdfSrv->GetDataSourceBlocking(url.get(),
553 getter_AddRefs( mFileMap ));
554 NS_ENSURE_TRUE( mFileMap, rv );
557 rv = rdfSrv->GetResource( aURL, getter_AddRefs( src ));
558 NS_ENSURE_SUCCESS(rv, rv );
559 rv = rdfSrv->GetResource(
560 NS_LITERAL_CSTRING("http://www.aasii.org/AA-rdf#File"),
561 getter_AddRefs( prop ));
562 NS_ENSURE_SUCCESS(rv, rv );
564 rv = mFileMap->GetTarget(src, prop, PR_TRUE, getter_AddRefs( target ));
565 if (! target)
566 return rv;
567 targetLiteral = do_QueryInterface( target, &rv );
568 NS_ENSURE_TRUE( target, rv );
569 targetLiteral->GetValueConst( result );
570 NS_ENSURE_TRUE( target, rv );
572 return NS_OK;
575 NS_IMETHODIMP
576 nsTestRunner::Notify(nsITimer *timer)
578 if (mArmed) {
579 mArmed = PR_FALSE;
580 AddError(nsITestRunner::errorTimeout, mTestID.get());
581 mTimer->Cancel();
583 traverse();
584 return NS_OK;
587 NS_IMETHODIMP
588 nsTestRunner::OnStateChange(nsIWebProgress *aWebProgress,
589 nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
591 if (! aStateFlags & nsIWebProgressListener::STATE_STOP )
592 return NS_OK;
594 nsCOMPtr<nsIDOMWindow> wnd;
595 aWebProgress->GetDOMWindow(getter_AddRefs( wnd ));
596 if ( wnd != mWatchWindow ) {
597 return NS_OK;
600 mWatchWindow = nsnull;
601 aWebProgress->RemoveProgressListener( this );
603 NS_ENSURE_TRUE(mArmed, NS_ERROR_UNEXPECTED);
605 nsITest *test = (nsITest *) mTestTree.Peek();
606 NS_ENSURE_TRUE(test, NS_ERROR_UNEXPECTED);
608 nsCOMPtr<nsIWebProgressListener> listener(do_QueryInterface(test));
609 NS_ENSURE_TRUE(listener, NS_ERROR_UNEXPECTED);
611 listener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
613 return NS_OK;
616 NS_IMETHODIMP
617 nsTestRunner::OnProgressChange(nsIWebProgress *aWebProgress,
618 nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
619 PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
621 return NS_ERROR_NOT_IMPLEMENTED;
624 NS_IMETHODIMP
625 nsTestRunner::OnLocationChange(nsIWebProgress *aWebProgress,
626 nsIRequest *aRequest, nsIURI *aLocation)
628 return NS_ERROR_NOT_IMPLEMENTED;
631 NS_IMETHODIMP
632 nsTestRunner::OnStatusChange(nsIWebProgress *aWebProgress,
633 nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
635 return NS_ERROR_NOT_IMPLEMENTED;
638 NS_IMETHODIMP
639 nsTestRunner::OnSecurityChange(nsIWebProgress *aWebProgress,
640 nsIRequest *aRequest, PRUint32 aState)
642 return NS_ERROR_NOT_IMPLEMENTED;
645 nsTestRunner*
646 nsTestRunner::GetTestRunner()
648 if ( nsTestRunner::gTestRunner == nsnull ) {
649 nsTestRunner::gTestRunner = new nsTestRunner;
652 if ( nsTestRunner::gTestRunner != nsnull ) {
653 NS_ADDREF( nsTestRunner::gTestRunner );
656 return nsTestRunner::gTestRunner;
659 /******************** nsFormatJSMessage ***********************************/
660 nsFormatJSMessage::nsFormatJSMessage(nsIConsoleMessage *aMessage)
661 :mIsChrome(PR_TRUE)
663 if (NS_SUCCEEDED( parseScriptError( aMessage ) )) {
664 return;
666 nsEmbedString wstr;
667 aMessage->GetMessage(getter_Copies( wstr ));
668 mFile.Assign(nsnull,0);
669 mLine = nsITestRunner::errorNoError;
670 mText.Assign( NS_ConvertUTF16toUTF8(wstr));
673 nsFormatJSMessage::nsFormatJSMessage(const char *aFile)
674 :mIsChrome(PR_TRUE)
676 mFile.Assign(aFile);
677 getSourceFile();
680 nsresult
681 nsFormatJSMessage::parseScriptError(nsIConsoleMessage *aMessage)
683 nsresult rv;
684 nsCOMPtr<nsIScriptError> error;
685 nsEmbedString wstr;
687 error = do_QueryInterface( aMessage, &rv );
688 if (NS_FAILED(rv))
689 return rv;
691 rv = formatErrorMessage(error);
692 NS_ENSURE_SUCCESS(rv, rv);
694 if (NS_FAILED( getSourceFile() )) {
695 mFile.Assign(nsnull, 0);
696 mLine = nsITestRunner::errorJS;
698 if (mFile.Length()>2 && !mIsChrome)
699 mLine++;
701 return NS_OK;
704 nsresult
705 nsFormatJSMessage::formatErrorMessage(nsIScriptError *error)
707 nsresult rv;
708 nsEmbedString wstr;
710 rv = error->GetErrorMessage( wstr );
711 NS_ENSURE_SUCCESS(rv, rv);
713 nsEmbedCString text = NS_ConvertUTF16toUTF8( wstr );
715 rv = error->GetLineNumber( &mLine );
716 if (NS_SUCCEEDED( rv ))
717 rv = error->GetSourceName( wstr );
718 if (NS_SUCCEEDED( rv ))
719 mFile = NS_ConvertUTF16toUTF8(wstr);
721 if ( parseException(text) )
722 return NS_OK;
724 PRUint32 flags;
725 rv = error->GetFlags( &flags );
726 if (NS_FAILED( rv ))
727 flags = 0;
729 if ( flags & nsIScriptError::warningFlag ) {
730 mText.Assign("warning: ");
731 } else {
732 mText.Assign("error: ");
734 mText.Append( text );
735 return NS_OK;
738 PRBool
739 nsFormatJSMessage::parseException(const nsACString &aMessage)
741 const char *head, *pos, *res, *end;
742 nsresult rv;
744 head = aMessage.BeginReading();
745 pos = strstr(head, "[Exception... \"");
746 if (! pos)
747 return PR_FALSE;
749 mText.Assign("exception: ");
751 if (pos[15] == '\'') {
752 end = strchr(&pos[16], '\'');
753 if (end) {
754 mText.Append(&pos[15], end - pos - 14);
756 } else if ( (res = strstr(&pos[15], "nsresult: \"0x")) && strlen(res) > 23) {
757 end = strchr(&res[23], ')');
758 if (end) {
759 mText.Append(&res[23], end - res - 23);
761 } else {
762 mText.Append(&pos[15],strlen(pos) - 16);
765 if ( ! mFile.Length() ) {
766 res = strstr(&pos[15],"location: \"JS frame :: ");
767 if (!res || strlen(res) < 25)
768 return PR_TRUE;
769 end = strstr(&res[23], " :: ");
770 if (! end)
771 return PR_TRUE;
772 mFile.Assign(Substring(&res[23], end - res - 23));
773 res = strstr(&end[4], ":: line ");
774 if (!res && strlen(res) < 10)
775 return PR_TRUE;
776 end = strchr(&res[8], '"');
777 if (! end)
778 return PR_TRUE;
779 mLine = Substring(&res[8], end - res - 8).ToInteger(&rv);
781 return PR_TRUE;
784 nsresult
785 nsFormatJSMessage::getSourceFile()
787 if ( StringHead(mFile, 7).Equals(NS_LITERAL_CSTRING("file://")) ) {
788 mIsChrome = PR_FALSE;
789 return parseLocalFile();
790 } else if (! StringHead(mFile, 9).Equals(NS_LITERAL_CSTRING("chrome://")) ) {
791 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
793 return parseChrome();
796 nsresult
797 nsFormatJSMessage::parseLocalFile()
799 nsEmbedCString leafName;
800 const PRUnichar* resolved;
802 leafName = "file://";
803 leafName += strrchr(mFile.BeginReading(), '/');
804 if (! mResolver) {
805 mResolver = nsTestRunner::GetTestRunner();
806 NS_ENSURE_TRUE( mResolver, NS_OK );
808 mResolver->resolve( leafName, &resolved );
809 if (! resolved )
810 return NS_OK;
811 if ( resolved[0] )
812 mFile.Assign(NS_ConvertUTF16toUTF8( resolved ));
814 return NS_OK;
817 nsresult
818 nsFormatJSMessage::parseChrome()
820 nsEmbedCString head;
821 const char *tail, *ptr = 0;
822 PRUint32 len;
823 const PRUnichar* resolved;
825 len = mFile.Length();
826 tail = strrchr(mFile.BeginReading(), '/');
827 head = StringHead(mFile, len - strlen(tail) );
828 if (! mResolver) {
829 mResolver = nsTestRunner::GetTestRunner();
830 NS_ENSURE_TRUE( mResolver, NS_OK );
832 mResolver->resolve( head, &resolved);
833 while( ! resolved && (head.Length() > 9) ) {
834 ptr = strrchr(head.BeginReading(), '/');
835 tail -= strlen(ptr);
836 head = StringHead(mFile, len - strlen(tail) );
837 mResolver->resolve( head, &resolved);
839 if (! resolved )
840 return NS_OK;
842 head = NS_ConvertUTF16toUTF8(resolved);
843 head += tail;
844 mFile.Assign( head );
846 return NS_OK;