Fleshed out SubstitutionField spec and implementation.
- Added newline modifier to spec and implementation - Does not belong in Merge, so moved back to glabels - Incorporated SubstitutionField into RawText
This commit is contained in:
@@ -112,6 +112,7 @@ set (glabels_sources
|
||||
Size.cpp
|
||||
StartupView.cpp
|
||||
StrUtil.cpp
|
||||
SubstitutionField.cpp
|
||||
Template.cpp
|
||||
TemplatePicker.cpp
|
||||
TemplatePickerItem.cpp
|
||||
@@ -256,6 +257,7 @@ set (glabels-batch_sources
|
||||
Settings.cpp
|
||||
Size.cpp
|
||||
StrUtil.cpp
|
||||
SubstitutionField.cpp
|
||||
Template.cpp
|
||||
TextNode.cpp
|
||||
Units.cpp
|
||||
@@ -336,6 +338,7 @@ link_directories (
|
||||
#=======================================
|
||||
add_subdirectory (BarcodeBackends)
|
||||
add_subdirectory (Merge)
|
||||
add_subdirectory (unit_tests)
|
||||
|
||||
|
||||
#=======================================
|
||||
|
||||
@@ -15,7 +15,6 @@ set (merge_sources
|
||||
TextColonKeys.cpp
|
||||
TextSemicolon.cpp
|
||||
TextSemicolonKeys.cpp
|
||||
SubstitutionField.cpp
|
||||
)
|
||||
|
||||
set (merge_qobject_headers
|
||||
@@ -44,7 +43,6 @@ link_directories (
|
||||
#=======================================
|
||||
# Subdirectories
|
||||
#=======================================
|
||||
add_subdirectory (unit_tests)
|
||||
|
||||
|
||||
#=======================================
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
/* SubstitutionField.cpp
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SubstitutionField.h"
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
|
||||
namespace glabels
|
||||
{
|
||||
|
||||
merge::SubstitutionField::SubstitutionField( const QString& string )
|
||||
{
|
||||
QStringRef s(&string);
|
||||
parseSubstitutionField( s );
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::evaluate( const merge::Record& record ) const
|
||||
{
|
||||
QString value = mDefaultValue;
|
||||
|
||||
if ( record.contains(mFieldName) )
|
||||
{
|
||||
value = record[mFieldName];
|
||||
}
|
||||
|
||||
if ( mFormatType.isNull() )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return formatValue( value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::fieldName() const
|
||||
{
|
||||
return mFieldName;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::defaultValue() const
|
||||
{
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::format() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
|
||||
QChar merge::SubstitutionField::formatType() const
|
||||
{
|
||||
return mFormatType;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::formatValue( const QString& value ) const
|
||||
{
|
||||
switch (mFormatType.unicode())
|
||||
{
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toLongLong(nullptr,0) );
|
||||
break;
|
||||
|
||||
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toULongLong(nullptr,0) );
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toDouble() );
|
||||
break;
|
||||
|
||||
case 's':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toStdString().c_str() );
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid format
|
||||
return "";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void merge::SubstitutionField::parseSubstitutionField( QStringRef& s )
|
||||
{
|
||||
if ( s.startsWith( "${" ) )
|
||||
{
|
||||
s = s.mid(2);
|
||||
parseFieldName( s );
|
||||
|
||||
while ( s.size() && s[0] == ':' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
parseModifier( s );
|
||||
}
|
||||
|
||||
if ( s.size() && s[0] == '}' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
|
||||
if ( s.size() )
|
||||
{
|
||||
// Invalid -- extraneous input
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid -- expected '}'
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid -- expected '${'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void merge::SubstitutionField::parseFieldName( QStringRef& s )
|
||||
{
|
||||
while ( s.size() && (s[0].isDigit() || s[0].isLetter() || s[0] == '_' || s[0] == '-') )
|
||||
{
|
||||
mFieldName.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void merge::SubstitutionField::parseModifier( QStringRef& s )
|
||||
{
|
||||
if ( s.size() && s[0] == '%' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
parseFormatModifier( s );
|
||||
}
|
||||
else if ( s.size() && s[0] == '=' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
parseDefaultValueModifier( s );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid -- unrecognized modifier, expecting one of '%' or '='
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void merge::SubstitutionField::parseDefaultValueModifier( QStringRef& s )
|
||||
{
|
||||
while ( s.size() && s[0] != ':' && s[0] != '}' )
|
||||
{
|
||||
if ( s[0] == '\\' )
|
||||
{
|
||||
s = s.mid(1); // Skip escape
|
||||
if ( s.size() )
|
||||
{
|
||||
mDefaultValue.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
{
|
||||
// Invalid -- end of string encountered during escape
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mDefaultValue.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void merge::SubstitutionField::parseFormatModifier( QStringRef& s )
|
||||
{
|
||||
mFormat = "%";
|
||||
|
||||
mFormat += parseFormatFlags( s );
|
||||
mFormat += parseFormatWidth( s );
|
||||
|
||||
if ( s.size() && s[0] == '.' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
mFormat += "." + parseFormatPrecision( s );
|
||||
}
|
||||
|
||||
mFormatType = parseFormatType( s );
|
||||
mFormat += mFormatType;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::parseFormatFlags( QStringRef& s )
|
||||
{
|
||||
QString flags;
|
||||
|
||||
while ( s.size() && QString( "-+ 0" ).contains( s[0] ) )
|
||||
{
|
||||
flags.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::parseFormatWidth( QStringRef& s )
|
||||
{
|
||||
return parseNaturalInteger( s );
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::parseFormatPrecision( QStringRef& s )
|
||||
{
|
||||
return parseNaturalInteger( s );
|
||||
}
|
||||
|
||||
|
||||
QChar merge::SubstitutionField::parseFormatType( QStringRef& s )
|
||||
{
|
||||
QChar type = 0;
|
||||
|
||||
if ( s.size() && QString( "diufFeEgGxXos" ).contains( s[0] ) )
|
||||
{
|
||||
type = s[0];
|
||||
s = s.mid(1);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
QString merge::SubstitutionField::parseNaturalInteger( QStringRef& s )
|
||||
{
|
||||
QString value = "";
|
||||
|
||||
if ( s.size() && s[0] >= '1' && s[0] <= '9' )
|
||||
{
|
||||
value += s[0];
|
||||
s = s.mid(1);
|
||||
|
||||
while ( s.size() && s[0].isDigit() )
|
||||
{
|
||||
value += s[0];
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
} // namespace glabels
|
||||
@@ -1,77 +0,0 @@
|
||||
/* SubstitutionField.h
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef glabels_SubstitutionField_h
|
||||
#define glabels_SubstitutionField_h
|
||||
|
||||
|
||||
#include "Record.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringRef>
|
||||
|
||||
|
||||
namespace glabels
|
||||
{
|
||||
|
||||
namespace merge
|
||||
{
|
||||
|
||||
class SubstitutionField
|
||||
{
|
||||
public:
|
||||
SubstitutionField() = default;
|
||||
SubstitutionField( const QString& string );
|
||||
|
||||
QString evaluate( const merge::Record& record ) const;
|
||||
|
||||
QString fieldName() const;
|
||||
QString defaultValue() const;
|
||||
QString format() const;
|
||||
QChar formatType() const;
|
||||
|
||||
private:
|
||||
QString formatValue( const QString& value ) const;
|
||||
void parseSubstitutionField( QStringRef& s );
|
||||
void parseFieldName( QStringRef& s );
|
||||
void parseModifier( QStringRef& s );
|
||||
void parseDefaultValueModifier( QStringRef& s );
|
||||
void parseFormatModifier( QStringRef& s );
|
||||
|
||||
QString parseFormatFlags( QStringRef& s );
|
||||
QString parseFormatWidth( QStringRef& s );
|
||||
QString parseFormatPrecision( QStringRef& s );
|
||||
QChar parseFormatType( QStringRef& s );
|
||||
QString parseNaturalInteger( QStringRef& s );
|
||||
|
||||
QString mFieldName;
|
||||
|
||||
QString mDefaultValue;
|
||||
|
||||
QString mFormat;
|
||||
QChar mFormatType;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // glabels_SubstitutionField_h
|
||||
@@ -1,222 +0,0 @@
|
||||
/* TestSubstitutionField.cpp
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TestSubstitutionField.h"
|
||||
|
||||
#include "SubstitutionField.h"
|
||||
|
||||
|
||||
QTEST_MAIN(TestSubstitutionField)
|
||||
|
||||
|
||||
void TestSubstitutionField::construction()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1234}" );
|
||||
QCOMPARE( f1.fieldName(), QString( "1234" ) );
|
||||
|
||||
glabels::merge::SubstitutionField f2( "${abc:=ABC}" );
|
||||
QCOMPARE( f2.fieldName(), QString( "abc" ) );
|
||||
QCOMPARE( f2.defaultValue(), QString( "ABC" ) );
|
||||
|
||||
glabels::merge::SubstitutionField f3( "${x:%08.2f}" );
|
||||
QCOMPARE( f3.fieldName(), QString( "x" ) );
|
||||
QCOMPARE( f3.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f3.formatType(), QChar('f') );
|
||||
|
||||
glabels::merge::SubstitutionField f4( "${y:%08.2f:=12.34}" );
|
||||
QCOMPARE( f4.fieldName(), QString( "y" ) );
|
||||
QCOMPARE( f4.defaultValue(), QString( "12.34" ) );
|
||||
QCOMPARE( f4.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f4.formatType(), QChar('f') );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::simpleEvaluation()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1}" );
|
||||
glabels::merge::SubstitutionField f2( "${2}" );
|
||||
glabels::merge::SubstitutionField f3( "${3}" );
|
||||
glabels::merge::SubstitutionField f4( "${4}" );
|
||||
|
||||
glabels::merge::Record record1;
|
||||
record1[ "1" ] = "Abcdefg";
|
||||
record1[ "2" ] = "Hijklmn";
|
||||
record1[ "3" ] = "Opqrstu";
|
||||
record1[ "4" ] = "Vwxyz!@";
|
||||
|
||||
QCOMPARE( f1.evaluate( record1 ), QString( "Abcdefg" ) );
|
||||
QCOMPARE( f2.evaluate( record1 ), QString( "Hijklmn" ) );
|
||||
QCOMPARE( f3.evaluate( record1 ), QString( "Opqrstu" ) );
|
||||
QCOMPARE( f4.evaluate( record1 ), QString( "Vwxyz!@" ) );
|
||||
|
||||
glabels::merge::Record record2;
|
||||
record2[ "1" ] = "1234567";
|
||||
record2[ "2" ] = "FooBar";
|
||||
record2[ "3" ] = "8901234";
|
||||
record2[ "4" ] = "#$%^&*";
|
||||
|
||||
QCOMPARE( f1.evaluate( record2 ), QString( "1234567" ) );
|
||||
QCOMPARE( f2.evaluate( record2 ), QString( "FooBar" ) );
|
||||
QCOMPARE( f3.evaluate( record2 ), QString( "8901234" ) );
|
||||
QCOMPARE( f4.evaluate( record2 ), QString( "#$%^&*" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::defaultValueEvaluation()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1:=foo1}" );
|
||||
glabels::merge::SubstitutionField f2( "${2:=foo2}" );
|
||||
glabels::merge::SubstitutionField f3( "${3:=foo3}" );
|
||||
glabels::merge::SubstitutionField f4( "${4:=foo4}" );
|
||||
|
||||
glabels::merge::Record record1;
|
||||
record1[ "1" ] = "Abcdefg";
|
||||
record1[ "2" ] = "Hijklmn";
|
||||
record1[ "3" ] = "Opqrstu";
|
||||
record1[ "4" ] = "Vwxyz!@";
|
||||
|
||||
QCOMPARE( f1.evaluate( record1 ), QString( "Abcdefg" ) );
|
||||
QCOMPARE( f2.evaluate( record1 ), QString( "Hijklmn" ) );
|
||||
QCOMPARE( f3.evaluate( record1 ), QString( "Opqrstu" ) );
|
||||
QCOMPARE( f4.evaluate( record1 ), QString( "Vwxyz!@" ) );
|
||||
|
||||
glabels::merge::Record record2; // All fields empty
|
||||
|
||||
QCOMPARE( f1.evaluate( record2 ), QString( "foo1" ) );
|
||||
QCOMPARE( f2.evaluate( record2 ), QString( "foo2" ) );
|
||||
QCOMPARE( f3.evaluate( record2 ), QString( "foo3" ) );
|
||||
QCOMPARE( f4.evaluate( record2 ), QString( "foo4" ) );
|
||||
|
||||
glabels::merge::Record record3;
|
||||
record3[ "1" ] = "xyzzy";
|
||||
// Field "2" empty
|
||||
// Field "3" empty
|
||||
record3[ "4" ] = "plugh";
|
||||
|
||||
QCOMPARE( f1.evaluate( record3 ), QString( "xyzzy" ) );
|
||||
QCOMPARE( f2.evaluate( record3 ), QString( "foo2" ) );
|
||||
QCOMPARE( f3.evaluate( record3 ), QString( "foo3" ) );
|
||||
QCOMPARE( f4.evaluate( record3 ), QString( "plugh" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedStringEvaluation()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1:%10s}" );
|
||||
glabels::merge::SubstitutionField f2( "${2:%10s}" );
|
||||
glabels::merge::SubstitutionField f3( "${3:%10s}" );
|
||||
glabels::merge::SubstitutionField f4( "${4:%10s}" );
|
||||
|
||||
glabels::merge::SubstitutionField f5( "${5:%-10s}" );
|
||||
glabels::merge::SubstitutionField f6( "${6:%-10s}" );
|
||||
glabels::merge::SubstitutionField f7( "${7:%-10s}" );
|
||||
glabels::merge::SubstitutionField f8( "${8:%-10s}" );
|
||||
|
||||
glabels::merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "0";
|
||||
record1[ "6" ] = "100";
|
||||
record1[ "7" ] = "-100";
|
||||
record1[ "8" ] = "3.14";
|
||||
|
||||
QCOMPARE( f1.evaluate( record1 ), QString( " 0" ) );
|
||||
QCOMPARE( f2.evaluate( record1 ), QString( " 1" ) );
|
||||
QCOMPARE( f3.evaluate( record1 ), QString( " -1" ) );
|
||||
QCOMPARE( f4.evaluate( record1 ), QString( " 3.14" ) );
|
||||
|
||||
QCOMPARE( f5.evaluate( record1 ), QString( "0 " ) );
|
||||
QCOMPARE( f6.evaluate( record1 ), QString( "100 " ) );
|
||||
QCOMPARE( f7.evaluate( record1 ), QString( "-100 " ) );
|
||||
QCOMPARE( f8.evaluate( record1 ), QString( "3.14 " ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedFloatEvaluation()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1:%+5.2f}" );
|
||||
glabels::merge::SubstitutionField f2( "${2:%+5.2f}" );
|
||||
glabels::merge::SubstitutionField f3( "${3:%+5.2f}" );
|
||||
glabels::merge::SubstitutionField f4( "${4:%+5.2f}" );
|
||||
|
||||
glabels::merge::SubstitutionField f5( "${5:%+5.2e}" );
|
||||
glabels::merge::SubstitutionField f6( "${6:%+5.2e}" );
|
||||
glabels::merge::SubstitutionField f7( "${7:%+5.2e}" );
|
||||
glabels::merge::SubstitutionField f8( "${8:%+5.2e}" );
|
||||
|
||||
glabels::merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "0";
|
||||
record1[ "6" ] = "100";
|
||||
record1[ "7" ] = "-100";
|
||||
record1[ "8" ] = "3.14";
|
||||
|
||||
QCOMPARE( f1.evaluate( record1 ), QString( "+0.00" ) );
|
||||
QCOMPARE( f2.evaluate( record1 ), QString( "+1.00" ) );
|
||||
QCOMPARE( f3.evaluate( record1 ), QString( "-1.00" ) );
|
||||
QCOMPARE( f4.evaluate( record1 ), QString( "+3.14" ) );
|
||||
|
||||
QCOMPARE( f5.evaluate( record1 ), QString( "+0.00e+00" ) );
|
||||
QCOMPARE( f6.evaluate( record1 ), QString( "+1.00e+02" ) );
|
||||
QCOMPARE( f7.evaluate( record1 ), QString( "-1.00e+02" ) );
|
||||
QCOMPARE( f8.evaluate( record1 ), QString( "+3.14e+00" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedIntEvaluation()
|
||||
{
|
||||
glabels::merge::SubstitutionField f1( "${1:%08d}" );
|
||||
glabels::merge::SubstitutionField f2( "${2:%08d}" );
|
||||
glabels::merge::SubstitutionField f3( "${3:%08d}" );
|
||||
glabels::merge::SubstitutionField f4( "${4:%08d}" );
|
||||
|
||||
glabels::merge::SubstitutionField f5( "${5:%08x}" );
|
||||
glabels::merge::SubstitutionField f6( "${6:%08x}" );
|
||||
glabels::merge::SubstitutionField f7( "${7:%08x}" );
|
||||
glabels::merge::SubstitutionField f8( "${8:%08x}" );
|
||||
|
||||
glabels::merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "100";
|
||||
record1[ "6" ] = "0x100";
|
||||
record1[ "7" ] = "-1";
|
||||
record1[ "8" ] = "314";
|
||||
|
||||
QCOMPARE( f1.evaluate( record1 ), QString( "00000000" ) );
|
||||
QCOMPARE( f2.evaluate( record1 ), QString( "00000001" ) );
|
||||
QCOMPARE( f3.evaluate( record1 ), QString( "-0000001" ) );
|
||||
QCOMPARE( f4.evaluate( record1 ), QString( "00000000" ) ); // Invalid integer value
|
||||
|
||||
QCOMPARE( f5.evaluate( record1 ), QString( "00000064" ) ); // 100(decimal) == 64(hex)
|
||||
QCOMPARE( f6.evaluate( record1 ), QString( "00000100" ) );
|
||||
QCOMPARE( f7.evaluate( record1 ), QString( "00000000" ) ); // Invalid unsigned integer
|
||||
QCOMPARE( f8.evaluate( record1 ), QString( "0000013a" ) ); // 314(decimal) == 13a(hex)
|
||||
}
|
||||
+54
-15
@@ -30,6 +30,7 @@ namespace glabels
|
||||
///
|
||||
RawText::RawText( const QString& string ) : mString(string)
|
||||
{
|
||||
tokenize();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +39,7 @@ namespace glabels
|
||||
///
|
||||
RawText::RawText( const char* cString ) : mString(QString(cString))
|
||||
{
|
||||
tokenize();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,24 +66,17 @@ namespace glabels
|
||||
///
|
||||
QString RawText::expand( merge::Record* record ) const
|
||||
{
|
||||
QString text = mString;
|
||||
QString text;
|
||||
|
||||
if ( record )
|
||||
foreach ( const Token& token, mTokens )
|
||||
{
|
||||
foreach ( QString key, record->keys() )
|
||||
if ( token.isField )
|
||||
{
|
||||
// Special case: remove line when it contains only an empty field.
|
||||
// e.g. an optional ${ADDR2} line. To bypass this case, include
|
||||
// whitespace at end of line.
|
||||
if ( record->value(key).isEmpty() )
|
||||
{
|
||||
QStringList v = text.split( '\n' );
|
||||
v.removeAll( "${"+key+"}" );
|
||||
text = v.join( '\n' );
|
||||
}
|
||||
|
||||
// Nominal case: simple replacement
|
||||
text.replace( "${"+key+"}", record->value(key) );
|
||||
text += token.field.evaluate( record );
|
||||
}
|
||||
else
|
||||
{
|
||||
text += token.text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,4 +102,48 @@ namespace glabels
|
||||
return mString.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Tokenize string
|
||||
///
|
||||
void RawText::tokenize()
|
||||
{
|
||||
Token token;
|
||||
|
||||
QStringRef s = &mString;
|
||||
while ( s.size() )
|
||||
{
|
||||
SubstitutionField field;
|
||||
if ( SubstitutionField::parse( s, field ) )
|
||||
{
|
||||
// Finalize current text token, if apropos
|
||||
if ( !token.text.isEmpty() )
|
||||
{
|
||||
token.isField = false;
|
||||
mTokens.append( token );
|
||||
}
|
||||
|
||||
// Create and finalize field token
|
||||
token.isField = true;
|
||||
token.text = "";
|
||||
token.field = field;
|
||||
mTokens.append( token );
|
||||
}
|
||||
else
|
||||
{
|
||||
token.text += s[0];
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize last text token, if apropos
|
||||
if ( !token.text.isEmpty() )
|
||||
{
|
||||
token.isField = false;
|
||||
mTokens.append( token );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace glabels
|
||||
|
||||
+16
-1
@@ -22,7 +22,7 @@
|
||||
#define RawText_h
|
||||
|
||||
|
||||
#include "Merge/Record.h"
|
||||
#include "SubstitutionField.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
@@ -55,12 +55,27 @@ namespace glabels
|
||||
bool isEmpty() const;
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
// Private Methods
|
||||
/////////////////////////////////
|
||||
private:
|
||||
void tokenize();
|
||||
|
||||
/////////////////////////////////
|
||||
// Private Data
|
||||
/////////////////////////////////
|
||||
private:
|
||||
QString mString;
|
||||
|
||||
struct Token
|
||||
{
|
||||
bool isField;
|
||||
QString text;
|
||||
SubstitutionField field;
|
||||
};
|
||||
|
||||
QList<Token> mTokens;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/* SubstitutionField.cpp
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SubstitutionField.h"
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
|
||||
namespace glabels
|
||||
{
|
||||
|
||||
SubstitutionField::SubstitutionField()
|
||||
: mNewLine(false), mFormatType(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SubstitutionField::SubstitutionField( const QString& string )
|
||||
: mNewLine(false), mFormatType(0)
|
||||
{
|
||||
QStringRef s(&string);
|
||||
parse( s, *this );
|
||||
}
|
||||
|
||||
|
||||
QString SubstitutionField::evaluate( const merge::Record* record ) const
|
||||
{
|
||||
QString value = mDefaultValue;
|
||||
|
||||
if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() )
|
||||
{
|
||||
value = record->value(mFieldName);
|
||||
}
|
||||
|
||||
if ( !mFormatType.isNull() )
|
||||
{
|
||||
value = formatValue( value );
|
||||
}
|
||||
|
||||
if ( record && record->contains(mFieldName) && !record->value(mFieldName).isEmpty() && mNewLine )
|
||||
{
|
||||
value = "\n" + value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
QString SubstitutionField::fieldName() const
|
||||
{
|
||||
return mFieldName;
|
||||
}
|
||||
|
||||
|
||||
QString SubstitutionField::defaultValue() const
|
||||
{
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
|
||||
QString SubstitutionField::format() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
|
||||
QChar SubstitutionField::formatType() const
|
||||
{
|
||||
return mFormatType;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::newLine() const
|
||||
{
|
||||
return mNewLine;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parse( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
QStringRef sTmp = s;
|
||||
|
||||
if ( sTmp.startsWith( "${" ) )
|
||||
{
|
||||
sTmp = sTmp.mid(2);
|
||||
|
||||
if ( parseFieldName( sTmp, field ) )
|
||||
{
|
||||
while ( sTmp.size() && sTmp[0] == ':' )
|
||||
{
|
||||
sTmp = sTmp.mid(1);
|
||||
if ( !parseModifier( sTmp, field ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( sTmp.size() && sTmp[0] == '}' )
|
||||
{
|
||||
sTmp = sTmp.mid(1);
|
||||
|
||||
// Success. Update s.
|
||||
s = sTmp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFieldName( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
while ( s.size() && (s[0].isDigit() || s[0].isLetter() || s[0] == '_' || s[0] == '-') )
|
||||
{
|
||||
field.mFieldName.append( s[0] );
|
||||
s = s.mid(1);
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseModifier( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if ( s.size() && s[0] == '%' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
success = parseFormatModifier( s, field );
|
||||
}
|
||||
else if ( s.size() && s[0] == '=' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
success = parseDefaultValueModifier( s, field );
|
||||
}
|
||||
else if ( s.size() && s[0] == 'n' )
|
||||
{
|
||||
s = s.mid(1);
|
||||
success = parseNewLineModifier( s, field );
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseDefaultValueModifier( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
field.mDefaultValue.clear();
|
||||
|
||||
while ( s.size() && !QString( ":}" ).contains( s[0] ) )
|
||||
{
|
||||
if ( s[0] == '\\' )
|
||||
{
|
||||
s = s.mid(1); // Skip escape
|
||||
if ( s.size() )
|
||||
{
|
||||
field.mDefaultValue.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
field.mDefaultValue.append( s[0] );
|
||||
s = s.mid(1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFormatModifier( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
field.mFormat = "%";
|
||||
|
||||
parseFormatFlags( s, field );
|
||||
parseFormatWidth( s, field );
|
||||
|
||||
if ( s.size() && s[0] == '.' )
|
||||
{
|
||||
field.mFormat += ".";
|
||||
s = s.mid(1);
|
||||
parseFormatPrecision( s, field );
|
||||
}
|
||||
|
||||
parseFormatType( s, field );
|
||||
|
||||
return true; // Don't let invalid formats kill entire SubstitutionField
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFormatFlags( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
while ( s.size() && QString( "-+ 0" ).contains( s[0] ) )
|
||||
{
|
||||
field.mFormat += s[0];
|
||||
s = s.mid(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFormatWidth( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
return parseNaturalInteger( s, field );
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFormatPrecision( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
return parseNaturalInteger( s, field );
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseFormatType( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if ( s.size() && QString( "diufFeEgGxXos" ).contains( s[0] ) )
|
||||
{
|
||||
field.mFormatType = s[0];
|
||||
field.mFormat += s[0];
|
||||
s = s.mid(1);
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseNaturalInteger( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if ( s.size() && s[0] >= '1' && s[0] <= '9' )
|
||||
{
|
||||
field.mFormat += s[0];
|
||||
s = s.mid(1);
|
||||
|
||||
while ( s.size() && s[0].isDigit() )
|
||||
{
|
||||
field.mFormat += s[0];
|
||||
s = s.mid(1);
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool SubstitutionField::parseNewLineModifier( QStringRef& s, SubstitutionField& field )
|
||||
{
|
||||
field.mNewLine = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString SubstitutionField::formatValue( const QString& value ) const
|
||||
{
|
||||
switch (mFormatType.unicode())
|
||||
{
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toLongLong(nullptr,0) );
|
||||
break;
|
||||
|
||||
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toULongLong(nullptr,0) );
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toDouble() );
|
||||
break;
|
||||
|
||||
case 's':
|
||||
return QString::asprintf( mFormat.toStdString().c_str(),
|
||||
value.toStdString().c_str() );
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid format
|
||||
return "";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace glabels
|
||||
@@ -0,0 +1,77 @@
|
||||
/* SubstitutionField.h
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef glabels_SubstitutionField_h
|
||||
#define glabels_SubstitutionField_h
|
||||
|
||||
|
||||
#include "Merge/Record.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringRef>
|
||||
|
||||
|
||||
namespace glabels
|
||||
{
|
||||
|
||||
class SubstitutionField
|
||||
{
|
||||
public:
|
||||
SubstitutionField();
|
||||
SubstitutionField( const QString& string );
|
||||
|
||||
QString evaluate( const merge::Record* record ) const;
|
||||
|
||||
QString fieldName() const;
|
||||
QString defaultValue() const;
|
||||
QString format() const;
|
||||
QChar formatType() const;
|
||||
bool newLine() const;
|
||||
|
||||
static bool parse( QStringRef& s, SubstitutionField& field );
|
||||
|
||||
private:
|
||||
static bool parseFieldName( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseModifier( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseDefaultValueModifier( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseFormatModifier( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseFormatFlags( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseFormatWidth( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseFormatPrecision( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseFormatType( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseNaturalInteger( QStringRef& s, SubstitutionField& field );
|
||||
static bool parseNewLineModifier( QStringRef& s, SubstitutionField& field );
|
||||
|
||||
QString formatValue( const QString& value ) const;
|
||||
|
||||
QString mFieldName;
|
||||
|
||||
QString mDefaultValue;
|
||||
|
||||
QString mFormat;
|
||||
QChar mFormatType;
|
||||
|
||||
bool mNewLine;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // glabels_SubstitutionField_h
|
||||
@@ -6,7 +6,7 @@ if (Qt5Test_FOUND)
|
||||
# Test SubstitutionField class
|
||||
#=======================================
|
||||
qt5_wrap_cpp (TestSubstitutionField_moc_sources TestSubstitutionField.h)
|
||||
add_executable (TestSubstitutionField TestSubstitutionField.cpp ${TestSubstitutionField_moc_sources})
|
||||
add_executable (TestSubstitutionField TestSubstitutionField.cpp ../SubstitutionField.cpp ${TestSubstitutionField_moc_sources})
|
||||
target_link_libraries (TestSubstitutionField Merge ${Qt5Core_LIBRARIES} ${Qt5Test_LIBRARIES} )
|
||||
add_test (NAME SubstitutionField COMMAND TestSubstitutionField)
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
/* TestSubstitutionField.cpp
|
||||
*
|
||||
* Copyright (C) 2017 Jim Evins <evins@snaught.com>
|
||||
*
|
||||
* This file is part of gLabels-qt.
|
||||
*
|
||||
* gLabels-qt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gLabels-qt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TestSubstitutionField.h"
|
||||
|
||||
#include "SubstitutionField.h"
|
||||
|
||||
|
||||
QTEST_MAIN(TestSubstitutionField)
|
||||
|
||||
|
||||
void TestSubstitutionField::parseValid()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
//
|
||||
// Valid substitution fields (concatenated in single input string)
|
||||
//
|
||||
QString input = "${1234}${abc:=ABC}${x:%08.2f}${y:%08.2f:=12.34}${ADDR2:n}";
|
||||
QStringRef s = &input;
|
||||
|
||||
SubstitutionField f1;
|
||||
QCOMPARE( SubstitutionField::parse( s, f1 ), true );
|
||||
QCOMPARE( f1.fieldName(), QString( "1234" ) );
|
||||
QCOMPARE( f1.newLine(), false );
|
||||
|
||||
SubstitutionField f2;
|
||||
QCOMPARE( SubstitutionField::parse( s, f2 ), true );
|
||||
QCOMPARE( f2.fieldName(), QString( "abc" ) );
|
||||
QCOMPARE( f2.defaultValue(), QString( "ABC" ) );
|
||||
QCOMPARE( f2.newLine(), false );
|
||||
|
||||
SubstitutionField f3;
|
||||
QCOMPARE( SubstitutionField::parse( s, f3 ), true );
|
||||
QCOMPARE( f3.fieldName(), QString( "x" ) );
|
||||
QCOMPARE( f3.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f3.formatType(), QChar('f') );
|
||||
QCOMPARE( f3.newLine(), false );
|
||||
|
||||
SubstitutionField f4;
|
||||
QCOMPARE( SubstitutionField::parse( s, f4 ), true );
|
||||
QCOMPARE( f4.fieldName(), QString( "y" ) );
|
||||
QCOMPARE( f4.defaultValue(), QString( "12.34" ) );
|
||||
QCOMPARE( f4.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f4.formatType(), QChar('f') );
|
||||
QCOMPARE( f4.newLine(), false );
|
||||
|
||||
SubstitutionField f5;
|
||||
QCOMPARE( SubstitutionField::parse( s, f5 ), true );
|
||||
QCOMPARE( f5.fieldName(), QString( "ADDR2" ) );
|
||||
QCOMPARE( f5.newLine(), true );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::parseInvalid()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
//
|
||||
// Ordinary text
|
||||
//
|
||||
QString input5 = "Abcdefg";
|
||||
QStringRef s5 = &input5;
|
||||
SubstitutionField f5;
|
||||
QCOMPARE( SubstitutionField::parse( s5, f5 ), false );
|
||||
QCOMPARE( s5, QStringRef( &input5 ) ); // Should not advance string reference
|
||||
|
||||
//
|
||||
// Invalid substitution fields (which are treated as ordinary text)
|
||||
//
|
||||
QString input6 = "$abc";
|
||||
QStringRef s6 = &input6;
|
||||
SubstitutionField f6;
|
||||
QCOMPARE( SubstitutionField::parse( s6, f6 ), false );
|
||||
QCOMPARE( s6, QStringRef( &input6 ) ); // Should not advance string reference
|
||||
|
||||
QString input7 = "${abc";
|
||||
QStringRef s7 = &input7;
|
||||
SubstitutionField f7;
|
||||
QCOMPARE( SubstitutionField::parse( s7, f7 ), false );
|
||||
QCOMPARE( s7, QStringRef( &input7 ) ); // Should not advance string reference
|
||||
|
||||
QString input8 = "${abc:}";
|
||||
QStringRef s8 = &input8;
|
||||
SubstitutionField f8;
|
||||
QCOMPARE( SubstitutionField::parse( s8, f8 ), false );
|
||||
QCOMPARE( s8, QStringRef( &input8 ) ); // Should not advance string reference
|
||||
|
||||
// Even though format is invalid, let it slide. Overall structure still good. Format will be ignored.
|
||||
QString input9 = "${abc:%3.2}";
|
||||
QStringRef s9 = &input9;
|
||||
SubstitutionField f9;
|
||||
QCOMPARE( SubstitutionField::parse( s9, f9 ), true );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::construction()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1234}" );
|
||||
QCOMPARE( f1.fieldName(), QString( "1234" ) );
|
||||
|
||||
SubstitutionField f2( "${abc:=ABC}" );
|
||||
QCOMPARE( f2.fieldName(), QString( "abc" ) );
|
||||
QCOMPARE( f2.defaultValue(), QString( "ABC" ) );
|
||||
|
||||
SubstitutionField f3( "${x:%08.2f}" );
|
||||
QCOMPARE( f3.fieldName(), QString( "x" ) );
|
||||
QCOMPARE( f3.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f3.formatType(), QChar('f') );
|
||||
|
||||
SubstitutionField f4( "${y:%08.2f:=12.34}" );
|
||||
QCOMPARE( f4.fieldName(), QString( "y" ) );
|
||||
QCOMPARE( f4.defaultValue(), QString( "12.34" ) );
|
||||
QCOMPARE( f4.format(), QString( "%08.2f" ) );
|
||||
QCOMPARE( f4.formatType(), QChar('f') );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::simpleEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1}" );
|
||||
SubstitutionField f2( "${2}" );
|
||||
SubstitutionField f3( "${3}" );
|
||||
SubstitutionField f4( "${4}" );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "1" ] = "Abcdefg";
|
||||
record1[ "2" ] = "Hijklmn";
|
||||
record1[ "3" ] = "Opqrstu";
|
||||
record1[ "4" ] = "Vwxyz!@";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record1 ), QString( "Abcdefg" ) );
|
||||
QCOMPARE( f2.evaluate( &record1 ), QString( "Hijklmn" ) );
|
||||
QCOMPARE( f3.evaluate( &record1 ), QString( "Opqrstu" ) );
|
||||
QCOMPARE( f4.evaluate( &record1 ), QString( "Vwxyz!@" ) );
|
||||
|
||||
merge::Record record2;
|
||||
record2[ "1" ] = "1234567";
|
||||
record2[ "2" ] = "FooBar";
|
||||
record2[ "3" ] = "8901234";
|
||||
record2[ "4" ] = "#$%^&*";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record2 ), QString( "1234567" ) );
|
||||
QCOMPARE( f2.evaluate( &record2 ), QString( "FooBar" ) );
|
||||
QCOMPARE( f3.evaluate( &record2 ), QString( "8901234" ) );
|
||||
QCOMPARE( f4.evaluate( &record2 ), QString( "#$%^&*" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::defaultValueEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1:=foo1}" );
|
||||
SubstitutionField f2( "${2:=foo2}" );
|
||||
SubstitutionField f3( "${3:=foo3}" );
|
||||
SubstitutionField f4( "${4:=foo4}" );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "1" ] = "Abcdefg";
|
||||
record1[ "2" ] = "Hijklmn";
|
||||
record1[ "3" ] = "Opqrstu";
|
||||
record1[ "4" ] = "Vwxyz!@";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record1 ), QString( "Abcdefg" ) );
|
||||
QCOMPARE( f2.evaluate( &record1 ), QString( "Hijklmn" ) );
|
||||
QCOMPARE( f3.evaluate( &record1 ), QString( "Opqrstu" ) );
|
||||
QCOMPARE( f4.evaluate( &record1 ), QString( "Vwxyz!@" ) );
|
||||
|
||||
merge::Record record2; // All fields empty
|
||||
|
||||
QCOMPARE( f1.evaluate( &record2 ), QString( "foo1" ) );
|
||||
QCOMPARE( f2.evaluate( &record2 ), QString( "foo2" ) );
|
||||
QCOMPARE( f3.evaluate( &record2 ), QString( "foo3" ) );
|
||||
QCOMPARE( f4.evaluate( &record2 ), QString( "foo4" ) );
|
||||
|
||||
merge::Record record3;
|
||||
record3[ "1" ] = "xyzzy";
|
||||
// Field "2" empty
|
||||
// Field "3" empty
|
||||
record3[ "4" ] = "plugh";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record3 ), QString( "xyzzy" ) );
|
||||
QCOMPARE( f2.evaluate( &record3 ), QString( "foo2" ) );
|
||||
QCOMPARE( f3.evaluate( &record3 ), QString( "foo3" ) );
|
||||
QCOMPARE( f4.evaluate( &record3 ), QString( "plugh" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedStringEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1:%10s}" );
|
||||
SubstitutionField f2( "${2:%10s}" );
|
||||
SubstitutionField f3( "${3:%10s}" );
|
||||
SubstitutionField f4( "${4:%10s}" );
|
||||
|
||||
SubstitutionField f5( "${5:%-10s}" );
|
||||
SubstitutionField f6( "${6:%-10s}" );
|
||||
SubstitutionField f7( "${7:%-10s}" );
|
||||
SubstitutionField f8( "${8:%-10s}" );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "0";
|
||||
record1[ "6" ] = "100";
|
||||
record1[ "7" ] = "-100";
|
||||
record1[ "8" ] = "3.14";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record1 ), QString( " 0" ) );
|
||||
QCOMPARE( f2.evaluate( &record1 ), QString( " 1" ) );
|
||||
QCOMPARE( f3.evaluate( &record1 ), QString( " -1" ) );
|
||||
QCOMPARE( f4.evaluate( &record1 ), QString( " 3.14" ) );
|
||||
|
||||
QCOMPARE( f5.evaluate( &record1 ), QString( "0 " ) );
|
||||
QCOMPARE( f6.evaluate( &record1 ), QString( "100 " ) );
|
||||
QCOMPARE( f7.evaluate( &record1 ), QString( "-100 " ) );
|
||||
QCOMPARE( f8.evaluate( &record1 ), QString( "3.14 " ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedFloatEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1:%+5.2f}" );
|
||||
SubstitutionField f2( "${2:%+5.2f}" );
|
||||
SubstitutionField f3( "${3:%+5.2f}" );
|
||||
SubstitutionField f4( "${4:%+5.2f}" );
|
||||
|
||||
SubstitutionField f5( "${5:%+5.2e}" );
|
||||
SubstitutionField f6( "${6:%+5.2e}" );
|
||||
SubstitutionField f7( "${7:%+5.2e}" );
|
||||
SubstitutionField f8( "${8:%+5.2e}" );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "0";
|
||||
record1[ "6" ] = "100";
|
||||
record1[ "7" ] = "-100";
|
||||
record1[ "8" ] = "3.14";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record1 ), QString( "+0.00" ) );
|
||||
QCOMPARE( f2.evaluate( &record1 ), QString( "+1.00" ) );
|
||||
QCOMPARE( f3.evaluate( &record1 ), QString( "-1.00" ) );
|
||||
QCOMPARE( f4.evaluate( &record1 ), QString( "+3.14" ) );
|
||||
|
||||
QCOMPARE( f5.evaluate( &record1 ), QString( "+0.00e+00" ) );
|
||||
QCOMPARE( f6.evaluate( &record1 ), QString( "+1.00e+02" ) );
|
||||
QCOMPARE( f7.evaluate( &record1 ), QString( "-1.00e+02" ) );
|
||||
QCOMPARE( f8.evaluate( &record1 ), QString( "+3.14e+00" ) );
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::formattedIntEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField f1( "${1:%08d}" );
|
||||
SubstitutionField f2( "${2:%08d}" );
|
||||
SubstitutionField f3( "${3:%08d}" );
|
||||
SubstitutionField f4( "${4:%08d}" );
|
||||
|
||||
SubstitutionField f5( "${5:%08x}" );
|
||||
SubstitutionField f6( "${6:%08x}" );
|
||||
SubstitutionField f7( "${7:%08x}" );
|
||||
SubstitutionField f8( "${8:%08x}" );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "1" ] = "0";
|
||||
record1[ "2" ] = "1";
|
||||
record1[ "3" ] = "-1";
|
||||
record1[ "4" ] = "3.14";
|
||||
|
||||
record1[ "5" ] = "100";
|
||||
record1[ "6" ] = "0x100";
|
||||
record1[ "7" ] = "-1";
|
||||
record1[ "8" ] = "314";
|
||||
|
||||
QCOMPARE( f1.evaluate( &record1 ), QString( "00000000" ) );
|
||||
QCOMPARE( f2.evaluate( &record1 ), QString( "00000001" ) );
|
||||
QCOMPARE( f3.evaluate( &record1 ), QString( "-0000001" ) );
|
||||
QCOMPARE( f4.evaluate( &record1 ), QString( "00000000" ) ); // Invalid integer value
|
||||
|
||||
QCOMPARE( f5.evaluate( &record1 ), QString( "00000064" ) ); // 100(decimal) == 64(hex)
|
||||
QCOMPARE( f6.evaluate( &record1 ), QString( "00000100" ) );
|
||||
QCOMPARE( f7.evaluate( &record1 ), QString( "00000000" ) ); // Invalid unsigned integer
|
||||
QCOMPARE( f8.evaluate( &record1 ), QString( "0000013a" ) ); // 314(decimal) == 13a(hex)
|
||||
}
|
||||
|
||||
|
||||
void TestSubstitutionField::newLineEvaluation()
|
||||
{
|
||||
using namespace glabels;
|
||||
|
||||
SubstitutionField addr2( "${ADDR2:n}" );
|
||||
QCOMPARE( addr2.fieldName(), QString( "ADDR2" ) );
|
||||
QCOMPARE( addr2.newLine(), true );
|
||||
|
||||
merge::Record record1;
|
||||
record1[ "ADDR2" ] = "Apt. 5B";
|
||||
|
||||
merge::Record record2;
|
||||
record2[ "ADDR2" ] = ""; // ADDR2 Empty
|
||||
|
||||
merge::Record record3;
|
||||
// ADDR2 not defined
|
||||
|
||||
QCOMPARE( addr2.evaluate( &record1 ), QString( "\nApt. 5B" ) ); // Prepends a newline
|
||||
QCOMPARE( addr2.evaluate( &record2 ), QString( "" ) ); // Evaluates empty
|
||||
QCOMPARE( addr2.evaluate( &record3 ), QString( "" ) ); // Evaluates empty
|
||||
}
|
||||
+3
@@ -26,12 +26,15 @@ class TestSubstitutionField : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void parseValid();
|
||||
void parseInvalid();
|
||||
void construction();
|
||||
void simpleEvaluation();
|
||||
void defaultValueEvaluation();
|
||||
void formattedStringEvaluation();
|
||||
void formattedFloatEvaluation();
|
||||
void formattedIntEvaluation();
|
||||
void newLineEvaluation();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user