Bug Bug 713381 - backout 38271572005b,d5ebbc25b4b8,6435f51dd10d. r=backout

This commit is contained in:
Chris Pearce 2012-01-19 11:56:54 +13:00
parent c7db97f406
commit feca30f47a
12 changed files with 129 additions and 469 deletions

View File

@ -1999,7 +1999,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
if (!decoder->Init(this)) {
LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
}
@ -2011,7 +2010,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsMediaStream* stream = originalStream->CloneData(decoder);
if (!stream) {
LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
}
@ -2019,7 +2017,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsresult rv = decoder->Load(stream, nsnull, aOriginal);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Failed to load decoder/stream for decoder %p", this, decoder.get()));
return rv;
}

View File

@ -193,7 +193,6 @@ nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
nsresult rv = aStream->Open(aStreamListener);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
delete aStream;
return rv;
}
@ -246,7 +245,6 @@ nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(mDecoderStateMachine,
"Must have state machine to start state machine thread");
NS_ENSURE_STATE(mDecoderStateMachine);
if (mShuttingDown)
return NS_OK;
@ -260,7 +258,6 @@ nsresult nsBuiltinDecoder::Play()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoderStateMachine != nsnull, "Should have state machine.");
nsresult res = ScheduleStateMachineThread();
NS_ENSURE_SUCCESS(res,res);
if (mPlayState == PLAY_STATE_SEEKING) {
@ -835,19 +832,29 @@ void nsBuiltinDecoder::ChangeState(PlayState aState)
}
mPlayState = aState;
if (mDecoderStateMachine) {
switch (aState) {
case PLAY_STATE_PLAYING:
mDecoderStateMachine->Play();
break;
case PLAY_STATE_SEEKING:
mDecoderStateMachine->Seek(mRequestedSeekTime);
mRequestedSeekTime = -1.0;
break;
default:
/* No action needed */
break;
}
switch (aState) {
case PLAY_STATE_PAUSED:
/* No action needed */
break;
case PLAY_STATE_PLAYING:
mDecoderStateMachine->Play();
break;
case PLAY_STATE_SEEKING:
mDecoderStateMachine->Seek(mRequestedSeekTime);
mRequestedSeekTime = -1.0;
break;
case PLAY_STATE_LOADING:
/* No action needed */
break;
case PLAY_STATE_START:
/* No action needed */
break;
case PLAY_STATE_ENDED:
/* No action needed */
break;
case PLAY_STATE_SHUTDOWN:
/* No action needed */
break;
}
mReentrantMonitor.NotifyAll();
}
@ -966,9 +973,7 @@ void nsBuiltinDecoder::Resume(bool aForceBuffering)
}
if (aForceBuffering) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mDecoderStateMachine) {
mDecoderStateMachine->StartBuffering();
}
mDecoderStateMachine->StartBuffering();
}
}

View File

@ -45,7 +45,6 @@
#include "mozilla/mozalloc.h"
#include "VideoUtils.h"
#include "nsTimeRanges.h"
#include "nsDeque.h"
#include "mozilla/Preferences.h"
#include "mozilla/StdInt.h"
@ -230,17 +229,6 @@ public:
return mStateMachineThread;
}
// Requests that a decode thread be created for aStateMachine. The thread
// may be created immediately, or after some delay, once a thread becomes
// available. The request can be cancelled using CancelCreateDecodeThread().
// It's the callers responsibility to not call this more than once for any
// given state machine.
nsresult RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
// Cancels a request made by RequestCreateDecodeThread to create a decode
// thread for aStateMachine.
nsresult CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
// Maximum number of active decode threads allowed. When more
// than this number are active the thread creation will fail.
static const PRUint32 MAX_DECODE_THREADS = 25;
@ -250,17 +238,16 @@ public:
// call with any other monitor held to avoid deadlock.
PRUint32 GetDecodeThreadCount();
// Keep track of the fact that a decode thread was created.
// Call on any thread. Holds the internal monitor so don't
// call with any other monitor held to avoid deadlock.
void NoteDecodeThreadCreated();
// Keep track of the fact that a decode thread was destroyed.
// Call on any thread. Holds the internal monitor so don't
// call with any other monitor held to avoid deadlock.
void NoteDecodeThreadDestroyed();
#ifdef DEBUG
// Returns true if aStateMachine has a pending request for a
// decode thread.
bool IsQueued(nsBuiltinDecoderStateMachine* aStateMachine);
#endif
private:
// Holds global instance of StateMachineTracker.
// Writable on main thread only.
@ -284,10 +271,6 @@ private:
// only, read from the decoder threads. Synchronized via
// the mMonitor.
nsIThread* mStateMachineThread;
// Queue of state machines waiting for decode threads. Entries at the front
// get their threads first.
nsDeque mPending;
};
StateMachineTracker* StateMachineTracker::mInstance = nsnull;
@ -313,23 +296,7 @@ void StateMachineTracker::EnsureGlobalStateMachine()
}
mStateMachineCount++;
}
#ifdef DEBUG
bool StateMachineTracker::IsQueued(nsBuiltinDecoderStateMachine* aStateMachine)
{
ReentrantMonitorAutoEnter mon(mMonitor);
PRInt32 size = mPending.GetSize();
for (int i = 0; i < size; ++i) {
nsBuiltinDecoderStateMachine* m =
static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
if (m == aStateMachine) {
return true;
}
}
return false;
}
#endif
void StateMachineTracker::CleanupGlobalStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -338,7 +305,6 @@ void StateMachineTracker::CleanupGlobalStateMachine()
mStateMachineCount--;
if (mStateMachineCount == 0) {
LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
{
ReentrantMonitorAutoEnter mon(mMonitor);
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mStateMachineThread);
@ -353,22 +319,16 @@ void StateMachineTracker::CleanupGlobalStateMachine()
}
}
void StateMachineTracker::NoteDecodeThreadCreated()
{
ReentrantMonitorAutoEnter mon(mMonitor);
++mDecodeThreadCount;
}
void StateMachineTracker::NoteDecodeThreadDestroyed()
{
ReentrantMonitorAutoEnter mon(mMonitor);
--mDecodeThreadCount;
while (mDecodeThreadCount < MAX_DECODE_THREADS && mPending.GetSize() > 0) {
nsBuiltinDecoderStateMachine* m =
static_cast<nsBuiltinDecoderStateMachine*>(mPending.PopFront());
nsresult rv;
{
ReentrantMonitorAutoExit exitMon(mMonitor);
rv = m->StartDecodeThread();
}
if (NS_SUCCEEDED(rv)) {
++mDecodeThreadCount;
}
}
}
PRUint32 StateMachineTracker::GetDecodeThreadCount()
@ -377,45 +337,6 @@ PRUint32 StateMachineTracker::GetDecodeThreadCount()
return mDecodeThreadCount;
}
nsresult StateMachineTracker::CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine) {
ReentrantMonitorAutoEnter mon(mMonitor);
PRInt32 size = mPending.GetSize();
for (PRInt32 i = 0; i < size; ++i) {
void* m = static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
if (m == aStateMachine) {
mPending.RemoveObjectAt(i);
break;
}
}
NS_ASSERTION(!IsQueued(aStateMachine), "State machine should no longer have queued request.");
return NS_OK;
}
nsresult StateMachineTracker::RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine)
{
NS_ENSURE_STATE(aStateMachine);
ReentrantMonitorAutoEnter mon(mMonitor);
if (mPending.GetSize() > 0 || mDecodeThreadCount + 1 >= MAX_DECODE_THREADS) {
// If there's already state machines in the queue, or we've exceeded the
// limit, append the state machine to the queue of state machines waiting
// for a decode thread. This ensures state machines already waiting get
// their threads first.
mPending.Push(aStateMachine);
return NS_OK;
}
nsresult rv;
{
ReentrantMonitorAutoExit exitMon(mMonitor);
rv = aStateMachine->StartDecodeThread();
}
if (NS_SUCCEEDED(rv)) {
++mDecodeThreadCount;
}
NS_ASSERTION(mDecodeThreadCount <= MAX_DECODE_THREADS,
"Should keep to thread limit!");
return NS_OK;
}
nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder,
nsBuiltinDecoderReader* aReader,
bool aRealTime) :
@ -446,7 +367,6 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
mDispatchedRunEvent(false),
mDecodeThreadWaiting(false),
mRealTime(aRealTime),
mRequestedNewDecodeThread(false),
mEventManager(aDecoder)
{
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
@ -466,10 +386,6 @@ nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Should not have a pending request for a new decode thread");
NS_ASSERTION(!mRequestedNewDecodeThread,
"Should not have (or flagged) a pending request for a new decode thread");
if (mTimer)
mTimer->Cancel();
mTimer = nsnull;
@ -1271,14 +1187,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
if (mRequestedNewDecodeThread) {
// We've requested that the decode be created, but it hasn't been yet.
// Cancel that request.
NS_ASSERTION(!mDecodeThread,
"Shouldn't have a decode thread until after request processed");
StateMachineTracker::Instance().CancelCreateDecodeThread(this);
mRequestedNewDecodeThread = false;
}
mStopDecodeThread = true;
mDecoder->GetReentrantMonitor().NotifyAll();
if (mDecodeThread) {
@ -1291,10 +1199,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
mDecodeThread = nsnull;
mDecodeThreadIdle = false;
}
NS_ASSERTION(!mRequestedNewDecodeThread,
"Any pending requests for decode threads must be canceled and unflagged");
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Any pending requests for decode threads must be canceled");
}
void nsBuiltinDecoderStateMachine::StopAudioThread()
@ -1313,68 +1217,52 @@ void nsBuiltinDecoderStateMachine::StopAudioThread()
}
nsresult
nsBuiltinDecoderStateMachine::ScheduleDecodeThread()
nsBuiltinDecoderStateMachine::StartDecodeThread()
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStopDecodeThread = false;
if (mState >= DECODER_STATE_COMPLETED) {
return NS_OK;
}
if (mDecodeThread) {
NS_ASSERTION(!mRequestedNewDecodeThread,
"Shouldn't have requested new decode thread when we have a decode thread");
// We already have a decode thread...
if (mDecodeThreadIdle) {
// ... and it's not been shutdown yet, wake it up.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
mDecodeThreadIdle = false;
}
return NS_OK;
} else if (!mRequestedNewDecodeThread) {
// We don't already have a decode thread, request a new one.
mRequestedNewDecodeThread = true;
PRUint32 count = 0;
bool created = false;
{
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
StateMachineTracker::Instance().RequestCreateDecodeThread(this);
}
return NS_OK;
}
nsresult
nsBuiltinDecoderStateMachine::StartDecodeThread()
{
NS_ASSERTION(StateMachineTracker::Instance().GetDecodeThreadCount() <
StateMachineTracker::MAX_DECODE_THREADS,
"Should not have reached decode thread limit");
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Should not already have a pending request for a new decode thread.");
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
mRequestedNewDecodeThread = false;
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
// Give up, report error to media element.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::DecodeError);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
return rv;
count = StateMachineTracker::Instance().GetDecodeThreadCount();
}
mStopDecodeThread = false;
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
return NS_OK;
if (!mDecodeThread && count > StateMachineTracker::MAX_DECODE_THREADS) {
// Have to run one iteration of the state machine loop to ensure the
// shutdown state is processed.
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
return NS_ERROR_FAILURE;
}
if (!mDecodeThread) {
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
// Have to run one iteration of the state machine loop to ensure the
// shutdown state is processed.
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
return rv;
}
created = true;
}
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
mDecodeThreadIdle = false;
if (created) {
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
StateMachineTracker::Instance().NoteDecodeThreadCreated();
}
return NS_OK;
}
@ -1390,7 +1278,6 @@ nsBuiltinDecoderStateMachine::StartAudioThread()
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
mState = DECODER_STATE_SHUTDOWN;
return rv;
}
@ -1748,7 +1635,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
case DECODER_STATE_DECODING_METADATA: {
// Ensure we have a decode thread to decode metadata.
return ScheduleDecodeThread();
return StartDecodeThread();
}
case DECODER_STATE_DECODING: {
@ -1772,7 +1659,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
// We're playing and/or our decode buffers aren't full. Ensure we have
// an active decode thread.
if (NS_FAILED(ScheduleDecodeThread())) {
if (NS_FAILED(StartDecodeThread())) {
NS_WARNING("Failed to start media decode thread!");
return NS_ERROR_FAILURE;
}
@ -1837,7 +1724,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
case DECODER_STATE_SEEKING: {
// Ensure we have a decode thread to perform the seek.
return ScheduleDecodeThread();
return StartDecodeThread();
}
case DECODER_STATE_COMPLETED: {

View File

@ -253,12 +253,6 @@ public:
// earlier, in which case the request is discarded.
nsresult ScheduleStateMachine(PRInt64 aUsecs);
// Creates and starts a new decode thread. Don't call this directly,
// request a new decode thread by calling
// StateMachineTracker::RequestCreateDecodeThread().
// The decoder monitor must not be held. Called on the state machine thread.
nsresult StartDecodeThread();
// Timer function to implement ScheduleStateMachine(aUsecs).
void TimeoutExpired();
@ -358,8 +352,7 @@ protected:
// here. Called on the audio thread.
PRUint32 PlayFromAudioQueue(PRUint64 aFrameOffset, PRUint32 aChannels);
// Stops the decode thread, and if we have a pending request for a new
// decode thread it is canceled. The decoder monitor must be held with exactly
// Stops the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
void StopDecodeThread();
@ -367,11 +360,9 @@ protected:
// one lock count. Called on the state machine thread.
void StopAudioThread();
// Ensures the decode thread is running if it already exists, or requests
// a new decode thread be started if there currently is no decode thread.
// The decoder monitor must be held with exactly one lock count. Called on
// the state machine thread.
nsresult ScheduleDecodeThread();
// Starts the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartDecodeThread();
// Starts the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
@ -634,10 +625,6 @@ protected:
// True is we are decoding a realtime stream, like a camera stream
bool mRealTime;
// True if we've requested a new decode thread, but it has not yet been
// created. Synchronized by the decoder monitor.
bool mRequestedNewDecodeThread;
PRUint32 mBufferingWait;
PRInt64 mLowDataThresholdUsecs;

View File

@ -150,7 +150,6 @@ _TEST_FILES = \
test_source_write.html \
test_standalone.html \
test_timeupdate_small_files.html \
test_too_many_elements.html \
test_volume.html \
test_video_to_canvas.html \
use_large_cache.js \

View File

@ -8,4 +8,4 @@ load 493915-1.html
skip-if(Android) load 495794-1.html
load 492286-1.xhtml
load 576612-1.html
skip-if(Android) load 691096-1.html # Android sound API can't handle playing large number of sounds at once.
load 691096-1.html

View File

@ -5,9 +5,9 @@
// These are small test files, good for just seeing if something loads. We
// really only need one test file per backend here.
var gSmallTests = [
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
{ name:"seek.webm", type:"video/webm", duration:3.966 },
{ name:"bogus.duh", type:"bogus/duh" }
];
@ -299,14 +299,6 @@ function getPlayableVideo(candidates) {
return null;
}
function getPlayableAudio(candidates) {
var v = document.createElement("audio");
var resources = candidates.filter(function(x){return /^audio/.test(x.type) && v.canPlayType(x.type);});
if (resources.length > 0)
return resources[0];
return null;
}
// Number of tests to run in parallel. Warning: Each media element requires
// at least 3 threads (4 on Linux), and on Linux each thread uses 10MB of
// virtual address space. Beware!

View File

@ -1,65 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=713381
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 713381</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=713381">Mozilla Bug 713381</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 713381 **/
const num = 500;
var ended = 0;
var finish = function(testNum) {
return function() {
ok(true, "Received ended event for instance " + testNum );
ended++;
if (ended == num) {
ok(true, "Should receive ended events for all " + num + " elements.");
SimpleTest.finish();
}
}
};
var resource = getPlayableAudio(gSmallTests);
if (resource == null) {
todo(false, "No types supported");
} else {
SimpleTest.waitForExplicitFinish();
// Load the resource, and play it to ensure it's entirely downloaded.
// Once it's played through, create a large number of audio elements which
// are the same resource. These will share data with the other resource, and
// so be really cheap to create.
var res = new Audio(resource.name);
res.addEventListener("ended",
function() {
for (var i=0; i<num; ++i) {
var a = new Audio(resource.name);
a.addEventListener("ended", finish(i), false);
a.volume = 0.1;
a.play();
}
}, false);
res.play();
}
</script>
</pre>
</body>
</html>

View File

@ -350,22 +350,6 @@ void* nsDeque::ObjectAt(PRInt32 aIndex) const {
return result;
}
void* nsDeque::RemoveObjectAt(PRInt32 aIndex) {
if ((aIndex<0) || (aIndex>=mSize)) {
return 0;
}
void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
// "Shuffle down" all elements in the array by 1, overwritting the element
// being removed.
for (PRInt32 i=aIndex; i<mSize; i++) {
mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
}
mSize--;
return result;
}
/**
* Create and return an iterator pointing to
* the beginning of the queue. Note that this

View File

@ -152,14 +152,6 @@ class NS_COM_GLUE nsDeque {
*/
void* ObjectAt(int aIndex) const;
/**
* Removes and returns the i'th member from the deque.
*
* @param index of desired item
* @return the element which was removed
*/
void* RemoveObjectAt(int aIndex);
/**
* Remove all items from container without destroying them.
*

View File

@ -89,7 +89,6 @@ CPP_UNIT_TESTS = \
TestCOMArray.cpp \
TestCOMPtr.cpp \
TestCOMPtrEq.cpp \
TestDeque.cpp \
TestFile.cpp \
TestHashtables.cpp \
TestID.cpp \
@ -110,6 +109,7 @@ endif
#CPP_UNIT_TESTS += \
# TestArray.cpp \
# TestCRT.cpp \
# TestDeque.cpp \
# TestEncoding.cpp \
# TestExpirationTracker.cpp \
# TestPipes.cpp \

View File

@ -35,7 +35,6 @@
*
* ***** END LICENSE BLOCK ***** */
#include "TestHarness.h"
#include "nsDeque.h"
#include "nsCRT.h"
#include <stdio.h>
@ -45,12 +44,13 @@
**************************************************************/
class _TestDeque {
public:
int Test();
private:
int OriginalTest();
int OriginalFlaw();
int AssignFlaw();
int TestRemove();
_TestDeque() {
SelfTest();
}
int SelfTest();
nsresult OriginalTest();
nsresult OriginalFlaw();
nsresult AssignFlaw();
};
static _TestDeque sTestDeque;
@ -60,214 +60,96 @@ class _Dealloc: public nsDequeFunctor {
}
};
#define TEST(aCondition, aMsg) \
if (!(aCondition)) { fail("TestDeque: "#aMsg); return 1; }
/**
* conduct automated self test for this class
*
* @param
* @return
*/
int _TestDeque::Test() {
int _TestDeque::SelfTest() {
/* the old deque should have failed a bunch of these tests */
int results=0;
results+=OriginalTest();
results+=OriginalFlaw();
results+=AssignFlaw();
results+=TestRemove();
return results;
}
int _TestDeque::OriginalTest() {
const int size = 200;
int ints[size];
nsresult _TestDeque::OriginalTest() {
int ints[200];
int count=sizeof(ints)/sizeof(int);
int i=0;
int temp;
int* temp;
nsDeque theDeque(new _Dealloc); //construct a simple one...
// ints = [0...199]
for (i=0;i<size;i++) { //initialize'em
ints[i]=i;
for (i=0;i<count;i++) { //initialize'em
ints[i]=10*(1+i);
}
// queue = [0...69]
for (i=0;i<70;i++) {
theDeque.Push(&ints[i]);
temp=*(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push #1");
TEST(theDeque.GetSize() == i + 1, "Verify size after push #1");
}
TEST(theDeque.GetSize() == 70, "Verify overall size after pushes #1");
// queue = [0...14]
for (i=1;i<=55;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 70-i, "Verify end after pop # 1");
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop # 1");
for (i=0;i<56;i++) {
temp=(int*)theDeque.Pop();
}
TEST(theDeque.GetSize() == 15, "Verify overall size after pops");
// queue = [0...14,0...54]
for (i=0;i<55;i++) {
theDeque.Push(&ints[i]);
temp=*(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push #2");
TEST(theDeque.GetSize() == i + 15 + 1, "Verify size after push # 2");
}
TEST(theDeque.GetSize() == 70, "Verify size after end of all pushes #2");
// queue = [0...14,0...19]
for (i=1;i<=35;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 55-i, "Verify end after pop # 2");
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop #2");
for (i=0;i<35;i++) {
temp=(int*)theDeque.Pop();
}
TEST(theDeque.GetSize() == 35, "Verify overall size after end of all pops #2");
// queue = [0...14,0...19,0...34]
for (i=0;i<35;i++) {
theDeque.Push(&ints[i]);
temp = *(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push # 3");
TEST(theDeque.GetSize() == 35 + 1 + i, "Verify size after push #3");
}
// queue = [0...14,0...19]
for (i=0;i<35;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 34 - i, "Verify end after pop # 3");
for (i=0;i<38;i++) {
temp=(int*)theDeque.Pop();
}
// queue = [0...14]
for (i=0;i<20;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 19 - i, "Verify end after pop # 4");
}
// queue = []
for (i=0;i<15;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 14 - i, "Verify end after pop # 5");
}
TEST(theDeque.GetSize() == 0, "Deque should finish empty.");
return 0;
return NS_OK;
}
int _TestDeque::OriginalFlaw() {
nsresult _TestDeque::OriginalFlaw() {
int ints[200];
int i=0;
int temp;
nsDeque d(new _Dealloc);
int* temp;
nsDeque secondDeque(new _Dealloc);
/**
* Test 1. Origin near end, semi full, call Peek().
* you start, mCapacity is 8
*/
printf("fill array\n");
for (i=0; i<30; i++)
ints[i]=i;
for (i=0; i<6; i++) {
d.Push(&ints[i]);
temp = *(int*)d.Peek();
TEST(temp == i, "OriginalFlaw push #1");
for (i=32; i; --i)
ints[i]=i*3+10;
printf("push 6 times\n");
for (i=0; i<6; i++)
secondDeque.Push(&ints[i]);
printf("popfront 4 times:\n");
for (i=4; i; --i) {
temp=(int*)secondDeque.PopFront();
printf("%d\t",*temp);
}
TEST(d.GetSize() == 6, "OriginalFlaw size check #1");
printf("push 4 times\n");
for (int j=4; j; --j)
secondDeque.Push(&ints[++i]);
printf("origin should now be about 4\n");
printf("and size should be 6\n");
printf("origin+size>capacity\n");
for (i=0; i<4; i++) {
temp=*(int*)d.PopFront();
TEST(temp == i, "PopFront test");
}
// d = [4,5]
TEST(d.GetSize() == 2, "OriginalFlaw size check #2");
/*<akk> Oh, I see ... it's a circular buffer */
printf("but the old code wasn't behaving accordingly.\n");
for (i=0; i<4; i++) {
d.Push(&ints[6 + i]);
}
// d = [4...9]
/*right*/
printf("we shouldn't crash or anything interesting, ");
for (i=4; i<=9; i++) {
temp=*(int*)d.PopFront();
TEST(temp == i, "OriginalFlaw empty check");
}
return 0;
temp=(int*)secondDeque.Peek();
printf("peek: %d\n",*temp);
return NS_OK;
}
int _TestDeque::AssignFlaw() {
nsresult _TestDeque::AssignFlaw() {
nsDeque src(new _Dealloc),dest(new _Dealloc);
return 0;
}
static bool VerifyContents(const nsDeque& aDeque, const int* aContents, int aLength) {
for (int i=0; i<aLength; ++i) {
if (*(int*)aDeque.ObjectAt(i) != aContents[i]) {
return false;
}
}
return true;
}
int _TestDeque::TestRemove() {
nsDeque d;
const int count = 10;
int ints[count];
for (int i=0; i<count; i++) {
ints[i] = i;
}
for (int i=0; i<6; i++) {
d.Push(&ints[i]);
}
// d = [0...5]
d.PopFront();
d.PopFront();
// d = [2,5]
for (int i=2; i<=5; i++) {
int t = *(int*)d.ObjectAt(i-2);
TEST(t == i, "Verify ObjectAt()");
}
d.RemoveObjectAt(1);
// d == [2,4,5]
static const int t1[] = {2,4,5};
TEST(VerifyContents(d, t1, 3), "verify contents t1");
d.PushFront(&ints[1]);
d.PushFront(&ints[0]);
d.PushFront(&ints[7]);
d.PushFront(&ints[6]);
// d == [6,7,0,1,2,4,5] // (0==mOrigin)
static const int t2[] = {6,7,0,1,2,4,5};
TEST(VerifyContents(d, t2, 7), "verify contents t2");
d.RemoveObjectAt(1);
// d == [6,0,1,2,4,5] // (1==mOrigin)
static const int t3[] = {6,0,1,2,4,5};
TEST(VerifyContents(d, t3, 6), "verify contents t3");
d.RemoveObjectAt(5);
// d == [6,0,1,2,4] // (1==mOrigin)
static const int t4[] = {6,0,1,2,4};
TEST(VerifyContents(d, t4, 5), "verify contents t4");
d.RemoveObjectAt(0);
// d == [0,1,2,4] // (2==mOrigin)
static const int t5[] = {0,1,2,4};
TEST(VerifyContents(d, t5, 4), "verify contents t5");
return 0;
return NS_OK;
}
int main (void) {
ScopedXPCOM xpcom("TestTimers");
NS_ENSURE_FALSE(xpcom.failed(), 1);
_TestDeque test;
int result = test.Test();
TEST(result == 0, "All tests pass");
return 0;
}