/*
* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* Test code for MTmSource functionality
*
*/
#include "TAGMA.H"
#include <e32test.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include "TAGMA_INTERNAL.H"
#endif
#define UNUSED_VAR(a) a = a
CTrapCleanup* TrapCleanup;
RTest test(_L("TTmSource - MTmSource tests"));
class TTestGraphicsDeviceMap : public MGraphicsDeviceMap
{
public:
TInt HorizontalTwipsToPixels(TInt a) const { return a; }
TInt VerticalTwipsToPixels(TInt a) const { return a; }
TInt HorizontalPixelsToTwips(TInt a) const { return a; }
TInt VerticalPixelsToTwips(TInt a) const { return a; }
TInt GetNearestFontInTwips(CFont*&,const TFontSpec&)
{
return KErrGeneral;
}
void ReleaseFont(CFont*) {}
};
class CTestPicture : public CPicture
{
public:
CTestPicture() {}
virtual void Draw(CGraphicsContext&, const TPoint&, const TRect&, MGraphicsDeviceMap*) const {}
virtual void ExternalizeL(RWriteStream&) const {}
virtual void GetOriginalSizeInTwips(TSize&) const {}
virtual TBool LineBreakPossible(TUint aClass,TBool aBeforePicture,TBool aHaveSpaces) const
{
++iRequestCount;
if (aBeforePicture)
{
test(aClass == iClassBefore);
test(aHaveSpaces == iSpacesBefore);
return iResultBefore;
}
test(aClass == iClassAfter);
test(aHaveSpaces == iSpacesAfter);
return iResultAfter;
}
// expected parameters for LineBreakPossible
TUint iClassBefore;
TUint iClassAfter;
TBool iSpacesBefore;
TBool iSpacesAfter;
// Results for breaking before/breaking after
TBool iResultBefore;
TBool iResultAfter;
mutable TInt iRequestCount;
};
class TTestSource : public MTmSource
{
public:
TTestSource() : iPicturePos(-1) {}
virtual ~TTestSource() {}
MGraphicsDeviceMap& FormatDevice() const { return iGDM; }
MGraphicsDeviceMap& InterpretDevice() const { return iGDM; }
TInt DocumentLength() const
{
return iText->Length();
}
void GetText(TInt aPos,TPtrC& aText, TTmCharFormat& aFormat) const
{
TTmCharFormat f;
aFormat = f;
aText.Set(iText->Mid(aPos));
}
void GetParagraphFormatL(TInt, RTmParFormat& aFormat) const
{
RTmParFormat p;
aFormat.CopyL(p);
}
CPicture* PictureL(TInt aPos) const
{
return aPos == iPicturePos? iPicture : 0;
}
TInt ParagraphStart(TInt) const { return 0; }
virtual TUint LineBreakClass(TUint aCode, TUint& aRangeStart,
TUint& aRangeEnd) const
{
if ('@' == aCode)
{
aRangeStart = aRangeEnd = aCode;
return ESaLineBreakClass;
}
if ('0' <= aCode && aCode <= '9')
{
aRangeStart = aRangeEnd = aCode;
return ELineBreakClasses + aCode - '0';
}
return MTmSource::LineBreakClass(aCode, aRangeStart, aRangeEnd);
}
virtual TBool LineBreakPossible(TUint aPrevClass, TUint aNextClass,
TBool aHaveSpaces) const
{
TInt first = static_cast<TInt>(aPrevClass);
TInt second = static_cast<TInt>(aNextClass);
TInt customCount = 0;
if (iDirection < 0)
{
first = aNextClass;
second = aPrevClass;
}
if (ELineBreakClasses <= first && first < ELineBreakClasses + 10)
{
++customCount;
test(first - ELineBreakClasses + '0' == FindNextCustomClass());
TInt countSpaces = CountSpaces();
test(!aHaveSpaces == !countSpaces);
}
if (ELineBreakClasses <= second && second < ELineBreakClasses + 10)
{
++customCount;
TInt c = FindNextCustomClass();
test(second - ELineBreakClasses + '0' == c);
}
if (0 == customCount)
return MTmSource::LineBreakPossible(aPrevClass, aNextClass, aHaveSpaces);
// Between custom and non-custom classes, allow a break only with spaces
// or between @ and 5
if (1 == customCount)
return aHaveSpaces
|| (first == ESaLineBreakClass && second == ELineBreakClasses + 5)
|| (second == ESaLineBreakClass && first == ELineBreakClasses + 5);
// Allow a break with spaces except after '0' or before '9'
if (aHaveSpaces)
return aPrevClass != ELineBreakClasses && aNextClass != ELineBreakClasses + 9;
// Allow a break only between a class and the class one more than it.
return aPrevClass + 1 == aNextClass;
}
virtual TBool GetLineBreakInContext(
const TDesC& aText, TInt aMinBreakPos, TInt aMaxBreakPos,
TBool aForwards,TInt& aBreakPos) const
{
test (iDirection == (aForwards? 1 : -1));
// The allowable break-points should not include the first
// and last characters of the run.
test (aMinBreakPos != 0);
for (TInt i = aMinBreakPos - 1; i <= aMaxBreakPos; ++i)
test('@' == aText[i]);
++iSaRequestCount;
aBreakPos = iText->Ptr() + iSaBreakpoint - aText.Ptr();
return aMinBreakPos <= aBreakPos && aBreakPos <= aMaxBreakPos;
}
virtual TBool IsHangingCharacter(TUint aChar) const
{
++iHangingCharRequestCount;
test(aChar == (*iText)[iMaxBreakPos]);
if (!iHangingChar)
return EFalse;
if (iDirection < 0)
++iCurrentPos;
return ETrue;
}
// non-virtual
TBool GetLineBreakL(const TDesC& aText, TInt aDocPos,
TInt aMinBreakPos, TInt aMaxBreakPos, TBool aForwards,
TInt& aBreakPos, TInt& aHangingChars, TInt& aBreakPosAfterSpaces) const
{
iText = &aText;
iMaxBreakPos = aMaxBreakPos;
iMinBreakPos = aMinBreakPos;
iHangingCharRequestCount = 0;
iSaRequestCount = 0;
iDirection = aForwards? 1 : -1;
iCurrentPos = aForwards? aMinBreakPos : aMaxBreakPos - 1;
TBool r = MTmSource::GetLineBreakL(aText, aDocPos,
aMinBreakPos, aMaxBreakPos, aForwards,
aBreakPos, aHangingChars, aBreakPosAfterSpaces);
if (r)
{
test(aMinBreakPos <= aBreakPos);
test(0 < aBreakPos);
test(aBreakPos <= aHangingChars);
test(aHangingChars <= aBreakPosAfterSpaces);
test(aBreakPos <= aMaxBreakPos);
test(aHangingChars == aBreakPos || iHangingChar);
// If the direction was backwards, the algorithm should have
// checked if a hanging character was allowed.
// This condition could be relaxed to allow it not to be checked
// if there is no break allowed between the possible hanging
// character and the previous character.
test(!aForwards || aText.Length() == aMaxBreakPos
|| 0 < iHangingCharRequestCount);
// If the maximum break point was chosen or exceeded, the algorithm
// should have checked to find out whether a hanging character is
// allowed.
test(aHangingChars < aMaxBreakPos
|| 0 < iHangingCharRequestCount);
// Check that only spaces exist between aHangingChars and
// aMaxBreakPos
for (TInt i = aHangingChars; i != aBreakPosAfterSpaces; ++i)
{
TUint n;
test(ESpLineBreakClass == LineBreakClass(aText[i], n, n));
}
// Check that all the spaces were counted
test(aBreakPosAfterSpaces == aText.Length()
|| aText[aBreakPosAfterSpaces] != ' ');
}
// Find out how many runs of two or more Sa there are, and check that
// this matches the number of times that it was requested.
TInt minChecked = aMinBreakPos - 1;
TInt maxChecked = aMaxBreakPos + 2;
if (r)
{
if (aForwards)
maxChecked = aBreakPos + 1;
else
minChecked = aBreakPos - 1;
}
if (minChecked < 0)
minChecked = 0;
if (aText.Length() < maxChecked)
maxChecked = aText.Length();
TInt runs = 0;
TInt sasSoFar = 0;
test (maxChecked - minChecked < 2
|| aText[minChecked] != '@'
|| aText[minChecked + 1] != '@'
|| !aForwards
|| aHangingChars == iSaBreakpoint);
for (; minChecked != maxChecked; ++minChecked)
{
if (aText[minChecked] == '@')
++sasSoFar;
else
{
if (1 < sasSoFar)
++runs;
sasSoFar = 0;
}
}
if (1 < sasSoFar)
++runs;
test(sasSoFar < 2 || aForwards || aHangingChars == iSaBreakpoint);
test(runs == iSaRequestCount);
return r;
}
TInt FindNextCustomClass() const
{
TInt end = iDirection < 0? -1 : iText->Length();
for (; iCurrentPos != end; iCurrentPos += iDirection)
{
TInt c = (*iText)[iCurrentPos];
if ('0' <= c && c <= '9')
return c;
}
return -1;
}
TInt CountSpaces() const
{
TInt end = iDirection < 0? -1 : iText->Length();
TInt count = 0;
if (iCurrentPos == end)
return 0;
iCurrentPos += iDirection;
for (; iCurrentPos != end; iCurrentPos += iDirection, ++count)
{
TInt c = (*iText)[iCurrentPos];
if (' ' != c)
return count;
}
return count;
}
private:
mutable TTestGraphicsDeviceMap iGDM;
mutable const TDesC* iText;
mutable TInt iMaxBreakPos;
mutable TInt iMinBreakPos;
mutable TInt iDirection;
mutable TInt iCurrentPos;
mutable TInt iHangingCharRequestCount;
mutable TInt iSaRequestCount;
public:
TInt iPicturePos;
CPicture* iPicture;
TBool iHangingChar;
TInt iSaBreakpoint;
};
TInt TestLineBreak(const TDesC& aText, TInt aSaBreak, TBool aHangingChar,
TInt aMin, TInt aMax, TBool aForwards)
{
if (aMax == 0)
aMax = aText.Length();
TTestSource t;
t.iHangingChar = aHangingChar;
t.iSaBreakpoint = aSaBreak;
TInt b0, b1, b2;
b0 = KMaxTInt;
b1 = KMaxTInt;
b2 = KMaxTInt;
return t.GetLineBreakL(aText, 0, aMin, aMax, aForwards, b0, b1, b2)?
b1 : -1;
}
void RunTests()
{
test.Title();
test.Start(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-TTMSOURCE-0001 Line-Break Tests: "));
test(-1 == TestLineBreak(_L(""), 0, 0, 0, 0, 0));
test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 0));
test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 1));
test(-1 == TestLineBreak(_L("@"), 1, 0, 0, 0, 0));
test(1 == TestLineBreak(_L("a b"), 0, 0, 0, 0, 0));
test(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 0));
test(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 1));
test(9 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 0));
test(5 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 1));
test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 0));
test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 1));
test(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 0));
test(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 1));
test(8 == TestLineBreak(_L("hel the re"), 0, 1, 5, 7, 0));
test(8 == TestLineBreak(_L("hel the re"), 0, 1, 6, 7, 1));
test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 0));
test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 1));
test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 0));
test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 1));
test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 0));
test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 1));
test(5 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 0));
test(2 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 1));
test(3 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 0));
test(2 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 1));
// Test for DEF046468, which was caused by the TLineBreakIterator constructor accessing past the end of a string
test.Next(_L("Line-Break DEF046468 Test:"));
// Create a string of 16 chars with a picture code at the 17th position
_LIT(KLarsString, "dolor sit amet, \xFFFC");
// Create a TPtrC for the 16 character string ( with the picture code after the string in memory )
TBufC<20> KTestBuffer(KLarsString);
TPtrC KTestString( reinterpret_cast<const TUint16*>(KTestBuffer.Ptr()), 16);
// Test the iterator overrun. If iterator accesses past the end of the array, it'll get picture code and crash
test(9 == TestLineBreak(KTestString,0,0,1,15,0));
test.End();
test.Close();
}
TInt E32Main()
{
TrapCleanup = CTrapCleanup::New();
TRAPD(err, RunTests());
test(err == KErrNone);
delete TrapCleanup;
return 0;
}