12851c541SNicolas Bonnefon /* 264c49544SNicolas Bonnefon * Copyright (C) 2009, 2010, 2011 Nicolas Bonnefon and other contributors 32851c541SNicolas Bonnefon * 42851c541SNicolas Bonnefon * This file is part of glogg. 52851c541SNicolas Bonnefon * 62851c541SNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify 72851c541SNicolas Bonnefon * it under the terms of the GNU General Public License as published by 82851c541SNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or 92851c541SNicolas Bonnefon * (at your option) any later version. 102851c541SNicolas Bonnefon * 112851c541SNicolas Bonnefon * glogg is distributed in the hope that it will be useful, 122851c541SNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of 132851c541SNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 142851c541SNicolas Bonnefon * GNU General Public License for more details. 152851c541SNicolas Bonnefon * 162851c541SNicolas Bonnefon * You should have received a copy of the GNU General Public License 172851c541SNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>. 182851c541SNicolas Bonnefon */ 192851c541SNicolas Bonnefon 20f35c72b9SNicolas Bonnefon #include <QSignalSpy> 21f35c72b9SNicolas Bonnefon #include <QMutexLocker> 22f35c72b9SNicolas Bonnefon #include <QFile> 23f35c72b9SNicolas Bonnefon 24f35c72b9SNicolas Bonnefon #include "testlogfiltereddata.h" 25f35c72b9SNicolas Bonnefon #include "logdata.h" 2620ec540aSNicolas Bonnefon #include "logfiltereddata.h" 27f35c72b9SNicolas Bonnefon 28f35c72b9SNicolas Bonnefon #if QT_VERSION < 0x040500 29f35c72b9SNicolas Bonnefon #define QBENCHMARK 30f35c72b9SNicolas Bonnefon #endif 31f35c72b9SNicolas Bonnefon 32f35c72b9SNicolas Bonnefon #if !defined( TMPDIR ) 33f35c72b9SNicolas Bonnefon #define TMPDIR "/tmp" 34f35c72b9SNicolas Bonnefon #endif 35f35c72b9SNicolas Bonnefon 365f0a91faSNicolas Bonnefon static const qint64 ML_NB_LINES = 15000LL; 375fc7617dSNicolas Bonnefon static const char* ml_format="LOGDATA is a part of glogg, we are going to test it thoroughly, this is line\t\t%06d\n"; 385fc7617dSNicolas Bonnefon static const int ML_VISIBLE_LINE_LENGTH = (76+8+4+6); // Without the final '\n' ! 39f35c72b9SNicolas Bonnefon 405f0a91faSNicolas Bonnefon static const qint64 SL_NB_LINES = 2000LL; 41f35c72b9SNicolas Bonnefon static const char* sl_format="LOGDATA is a part of glogg, we are going to test it thoroughly, this is line %06d\n"; 42f35c72b9SNicolas Bonnefon 437ab70cd2SNicolas Bonnefon static const char* partial_line_begin = "123... beginning of line."; 447ab70cd2SNicolas Bonnefon static const char* partial_line_end = " end of line 123.\n"; 457ab70cd2SNicolas Bonnefon 467ab70cd2SNicolas Bonnefon static const char* partial_nonmatching_line_begin = "Beginning of line."; 477ab70cd2SNicolas Bonnefon 480b28d87cSNicolas Bonnefon TestLogFilteredData::TestLogFilteredData() : QObject(), 490b28d87cSNicolas Bonnefon loadingFinishedMutex_(), 500b28d87cSNicolas Bonnefon searchProgressedMutex_(), 510b28d87cSNicolas Bonnefon loadingFinishedCondition_(), 520b28d87cSNicolas Bonnefon searchProgressedCondition_() 530b28d87cSNicolas Bonnefon { 540b28d87cSNicolas Bonnefon loadingFinished_received_ = false; 550b28d87cSNicolas Bonnefon loadingFinished_read_ = false; 560b28d87cSNicolas Bonnefon searchProgressed_received_ = false; 570b28d87cSNicolas Bonnefon searchProgressed_read_ = false; 580b28d87cSNicolas Bonnefon } 590b28d87cSNicolas Bonnefon 60f35c72b9SNicolas Bonnefon void TestLogFilteredData::initTestCase() 61f35c72b9SNicolas Bonnefon { 62f35c72b9SNicolas Bonnefon QVERIFY( generateDataFiles() ); 63f35c72b9SNicolas Bonnefon } 64f35c72b9SNicolas Bonnefon 65f35c72b9SNicolas Bonnefon void TestLogFilteredData::simpleSearch() 66f35c72b9SNicolas Bonnefon { 670b28d87cSNicolas Bonnefon logData_ = new LogData(); 68f35c72b9SNicolas Bonnefon 69f35c72b9SNicolas Bonnefon // Register for notification file is loaded 700b28d87cSNicolas Bonnefon connect( logData_, SIGNAL( loadingFinished( bool ) ), 71f35c72b9SNicolas Bonnefon this, SLOT( loadingFinished() ) ); 72f35c72b9SNicolas Bonnefon 730b28d87cSNicolas Bonnefon filteredData_ = logData_->getNewFilteredData(); 740b28d87cSNicolas Bonnefon connect( filteredData_, SIGNAL( searchProgressed( int, int ) ), 75f35c72b9SNicolas Bonnefon this, SLOT( searchProgressed( int, int ) ) ); 76f35c72b9SNicolas Bonnefon 770b28d87cSNicolas Bonnefon QFuture<void> future = QtConcurrent::run(this, &TestLogFilteredData::simpleSearchTest); 78f35c72b9SNicolas Bonnefon 790b28d87cSNicolas Bonnefon QApplication::exec(); 800b28d87cSNicolas Bonnefon 810b28d87cSNicolas Bonnefon disconnect( filteredData_, 0 ); 820b28d87cSNicolas Bonnefon disconnect( logData_, 0 ); 830b28d87cSNicolas Bonnefon 840b28d87cSNicolas Bonnefon delete filteredData_; 850b28d87cSNicolas Bonnefon delete logData_; 860b28d87cSNicolas Bonnefon } 870b28d87cSNicolas Bonnefon 880b28d87cSNicolas Bonnefon void TestLogFilteredData::simpleSearchTest() 890b28d87cSNicolas Bonnefon { 900b28d87cSNicolas Bonnefon // First load the tests file 910b28d87cSNicolas Bonnefon logData_->attachFile( TMPDIR "/mediumlog.txt" ); 920b28d87cSNicolas Bonnefon // Wait for the loading to be done 930b28d87cSNicolas Bonnefon waitLoadingFinished(); 940b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), ML_NB_LINES ); 950b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 960b28d87cSNicolas Bonnefon 970b28d87cSNicolas Bonnefon // Now perform a simple search 985f0a91faSNicolas Bonnefon qint64 matches[] = { 0, 15, 20, 135 }; 990ed63e59SNicolas Bonnefon QBENCHMARK { 100f35c72b9SNicolas Bonnefon // Start the search 1010b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "123" ) ); 102f35c72b9SNicolas Bonnefon 103f35c72b9SNicolas Bonnefon // And check we receive data in 4 chunks (the first being empty) 104f35c72b9SNicolas Bonnefon for ( int i = 0; i < 4; i++ ) { 1050b28d87cSNicolas Bonnefon std::pair<int,int> progress = waitSearchProgressed(); 1065f12ccbaSNicolas Bonnefon // FIXME: The test for this is unfortunately not reliable 1075f12ccbaSNicolas Bonnefon // (race conditions) 1085f12ccbaSNicolas Bonnefon // QCOMPARE( (qint64) progress.first, matches[i] ); 1090b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 110f35c72b9SNicolas Bonnefon } 1110ed63e59SNicolas Bonnefon } 1120ed63e59SNicolas Bonnefon 1130b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), matches[3] ); 114f35c72b9SNicolas Bonnefon // Check the search 1150b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->isLineInMatchingList( 123 ), true ); 1160b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->isLineInMatchingList( 124 ), false ); 1170b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), ML_VISIBLE_LINE_LENGTH ); 1180b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getLineLength( 12 ), ML_VISIBLE_LINE_LENGTH ); 1190b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 135LL ); 120f35c72b9SNicolas Bonnefon // Line beyond limit 1210b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->isLineInMatchingList( 60000 ), false ); 1220b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getMatchingLineNumber( 0 ), 123LL ); 123f35c72b9SNicolas Bonnefon 1240ed63e59SNicolas Bonnefon // Now let's try interrupting a search 1250b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "123" ) ); 1260ed63e59SNicolas Bonnefon // ... wait for two chunks. 1270b28d87cSNicolas Bonnefon waitSearchProgressed(); 1280b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 1290ed63e59SNicolas Bonnefon // and interrupt! 1300b28d87cSNicolas Bonnefon filteredData_->interruptSearch(); 1315f12ccbaSNicolas Bonnefon 1325f12ccbaSNicolas Bonnefon { 1335f12ccbaSNicolas Bonnefon std::pair<int,int> progress; 1345f12ccbaSNicolas Bonnefon do { 1355f12ccbaSNicolas Bonnefon progress = waitSearchProgressed(); 1360b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 1375f12ccbaSNicolas Bonnefon } while ( progress.second < 100 ); 1380ed63e59SNicolas Bonnefon 1390ed63e59SNicolas Bonnefon // (because there is no guarantee when the search is 1400ed63e59SNicolas Bonnefon // interrupted, we are not sure how many chunk of result 1410ed63e59SNicolas Bonnefon // we will get.) 1425f12ccbaSNicolas Bonnefon } 1430ed63e59SNicolas Bonnefon 1440b28d87cSNicolas Bonnefon QApplication::quit(); 145f35c72b9SNicolas Bonnefon } 146f35c72b9SNicolas Bonnefon 147f35c72b9SNicolas Bonnefon void TestLogFilteredData::multipleSearch() 148f35c72b9SNicolas Bonnefon { 1490b28d87cSNicolas Bonnefon logData_ = new LogData(); 150f35c72b9SNicolas Bonnefon 151f35c72b9SNicolas Bonnefon // Register for notification file is loaded 1520b28d87cSNicolas Bonnefon connect( logData_, SIGNAL( loadingFinished( bool ) ), 153f35c72b9SNicolas Bonnefon this, SLOT( loadingFinished() ) ); 154f35c72b9SNicolas Bonnefon 1550b28d87cSNicolas Bonnefon filteredData_ = logData_->getNewFilteredData(); 1560b28d87cSNicolas Bonnefon connect( filteredData_, SIGNAL( searchProgressed( int, int ) ), 157f35c72b9SNicolas Bonnefon this, SLOT( searchProgressed( int, int ) ) ); 158f35c72b9SNicolas Bonnefon 1590b28d87cSNicolas Bonnefon QFuture<void> future = QtConcurrent::run(this, &TestLogFilteredData::multipleSearchTest); 1600b28d87cSNicolas Bonnefon 1610b28d87cSNicolas Bonnefon QApplication::exec(); 1620b28d87cSNicolas Bonnefon 1630b28d87cSNicolas Bonnefon disconnect( filteredData_, 0 ); 1640b28d87cSNicolas Bonnefon disconnect( logData_, 0 ); 1650b28d87cSNicolas Bonnefon 1660b28d87cSNicolas Bonnefon delete filteredData_; 1670b28d87cSNicolas Bonnefon delete logData_; 1680b28d87cSNicolas Bonnefon } 1690b28d87cSNicolas Bonnefon 1700b28d87cSNicolas Bonnefon void TestLogFilteredData::multipleSearchTest() 1710b28d87cSNicolas Bonnefon { 1720b28d87cSNicolas Bonnefon // First load the tests file 1730b28d87cSNicolas Bonnefon logData_->attachFile( TMPDIR "/smalllog.txt" ); 1740b28d87cSNicolas Bonnefon // Wait for the loading to be done 1750b28d87cSNicolas Bonnefon waitLoadingFinished(); 1760b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), SL_NB_LINES ); 1770b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 1780b28d87cSNicolas Bonnefon 1790b28d87cSNicolas Bonnefon // Performs two searches in a row 180f35c72b9SNicolas Bonnefon // Start the search, and immediately another one 1810ed63e59SNicolas Bonnefon // (the second call should block until the first search is done) 1820b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "1234" ) ); 1830b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "123" ) ); 184f35c72b9SNicolas Bonnefon 1850b28d87cSNicolas Bonnefon for ( int i = 0; i < 3; i++ ) { 1860b28d87cSNicolas Bonnefon waitSearchProgressed(); 1870b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 1880b28d87cSNicolas Bonnefon } 189f35c72b9SNicolas Bonnefon 1900b28d87cSNicolas Bonnefon // We should have the result for the 2nd search after the last chunk 1910b28d87cSNicolas Bonnefon waitSearchProgressed(); 1920b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 12LL ); 1930b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 1940ed63e59SNicolas Bonnefon 1950ed63e59SNicolas Bonnefon // Now a tricky one: we run a search and immediately attach a new file 1965f12ccbaSNicolas Bonnefon /* FIXME: sometimes we receive loadingFinished before searchProgressed 1975f12ccbaSNicolas Bonnefon * -> deadlock in the test. 1980b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "123" ) ); 1990b28d87cSNicolas Bonnefon waitSearchProgressed(); 2000b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 2010b28d87cSNicolas Bonnefon logData_->attachFile( TMPDIR "/mediumlog.txt" ); 2020ed63e59SNicolas Bonnefon 2030ed63e59SNicolas Bonnefon // We don't expect meaningful results but it should not crash! 2040b28d87cSNicolas Bonnefon for ( int i = 0; i < 1; i++ ) { 2050b28d87cSNicolas Bonnefon waitSearchProgressed(); 2060b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 2070b28d87cSNicolas Bonnefon } 2085f12ccbaSNicolas Bonnefon */ 2095f12ccbaSNicolas Bonnefon 2105f12ccbaSNicolas Bonnefon sleep(10); 2110ed63e59SNicolas Bonnefon 2120b28d87cSNicolas Bonnefon QApplication::quit(); 213f35c72b9SNicolas Bonnefon } 214f35c72b9SNicolas Bonnefon 215ba40a297SNicolas Bonnefon void TestLogFilteredData::updateSearch() 216ba40a297SNicolas Bonnefon { 2170b28d87cSNicolas Bonnefon logData_ = new LogData(); 218ba40a297SNicolas Bonnefon 219ba40a297SNicolas Bonnefon // Register for notification file is loaded 2200b28d87cSNicolas Bonnefon connect( logData_, SIGNAL( loadingFinished( bool ) ), 221ba40a297SNicolas Bonnefon this, SLOT( loadingFinished() ) ); 222ba40a297SNicolas Bonnefon 2230b28d87cSNicolas Bonnefon filteredData_ = logData_->getNewFilteredData(); 2240b28d87cSNicolas Bonnefon connect( filteredData_, SIGNAL( searchProgressed( int, int ) ), 225ba40a297SNicolas Bonnefon this, SLOT( searchProgressed( int, int ) ) ); 226ba40a297SNicolas Bonnefon 2270b28d87cSNicolas Bonnefon QFuture<void> future = QtConcurrent::run(this, &TestLogFilteredData::updateSearchTest); 228ba40a297SNicolas Bonnefon 229ba40a297SNicolas Bonnefon QApplication::exec(); 230ba40a297SNicolas Bonnefon 2310b28d87cSNicolas Bonnefon disconnect( filteredData_, 0 ); 2320b28d87cSNicolas Bonnefon disconnect( logData_, 0 ); 2330b28d87cSNicolas Bonnefon 2340b28d87cSNicolas Bonnefon delete filteredData_; 2350b28d87cSNicolas Bonnefon delete logData_; 2360b28d87cSNicolas Bonnefon } 2370b28d87cSNicolas Bonnefon 2380b28d87cSNicolas Bonnefon void TestLogFilteredData::updateSearchTest() 2390b28d87cSNicolas Bonnefon { 2400b28d87cSNicolas Bonnefon // First load the tests file 2410b28d87cSNicolas Bonnefon logData_->attachFile( TMPDIR "/smalllog.txt" ); 2420b28d87cSNicolas Bonnefon // Wait for the loading to be done 2430b28d87cSNicolas Bonnefon waitLoadingFinished(); 2440b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), SL_NB_LINES ); 2450b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 2460b28d87cSNicolas Bonnefon 2470b28d87cSNicolas Bonnefon // Perform a first search 2480b28d87cSNicolas Bonnefon filteredData_->runSearch( QRegExp( "123" ) ); 2490b28d87cSNicolas Bonnefon 2500b28d87cSNicolas Bonnefon for ( int i = 0; i < 2; i++ ) { 2510b28d87cSNicolas Bonnefon waitSearchProgressed(); 2520b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 2530b28d87cSNicolas Bonnefon } 2540b28d87cSNicolas Bonnefon 255ba40a297SNicolas Bonnefon // Check the result 2560b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 12LL ); 257ba40a297SNicolas Bonnefon 2585f12ccbaSNicolas Bonnefon sleep(1); 2595f12ccbaSNicolas Bonnefon 2607d862d7eSNicolas Bonnefon QWARN("Starting stage 2"); 2617d862d7eSNicolas Bonnefon 262ba40a297SNicolas Bonnefon // Add some data to the file 263ba40a297SNicolas Bonnefon char newLine[90]; 264ba40a297SNicolas Bonnefon QFile file( TMPDIR "/smalllog.txt" ); 265ba40a297SNicolas Bonnefon if ( file.open( QIODevice::Append ) ) { 266ba40a297SNicolas Bonnefon for (int i = 0; i < 3000; i++) { 267ba40a297SNicolas Bonnefon snprintf(newLine, 89, sl_format, i); 268ba40a297SNicolas Bonnefon file.write( newLine, qstrlen(newLine) ); 269ba40a297SNicolas Bonnefon } 2707ab70cd2SNicolas Bonnefon // To test the edge case when the final line is not complete and matching 2717ab70cd2SNicolas Bonnefon file.write( partial_line_begin, qstrlen( partial_line_begin ) ); 272ba40a297SNicolas Bonnefon } 273ba40a297SNicolas Bonnefon file.close(); 274ba40a297SNicolas Bonnefon 2755f12ccbaSNicolas Bonnefon // Let the system do the update (there might be several ones) 2765f12ccbaSNicolas Bonnefon do { 2770b28d87cSNicolas Bonnefon waitLoadingFinished(); 2780b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 2795f12ccbaSNicolas Bonnefon } while ( logData_->getNbLine() < 5001LL ); 2805f12ccbaSNicolas Bonnefon 2815f12ccbaSNicolas Bonnefon sleep(1); 2825db60fd3SNicolas Bonnefon 283ba40a297SNicolas Bonnefon // Start an update search 2840b28d87cSNicolas Bonnefon filteredData_->updateSearch(); 285ba40a297SNicolas Bonnefon 2860b28d87cSNicolas Bonnefon for ( int i = 0; i < 2; i++ ) { 2870b28d87cSNicolas Bonnefon waitSearchProgressed(); 2880b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 2890b28d87cSNicolas Bonnefon } 290ba40a297SNicolas Bonnefon 291ba40a297SNicolas Bonnefon // Check the result 2920b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), 5001LL ); 2930b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 26LL ); 2947ab70cd2SNicolas Bonnefon 2957d862d7eSNicolas Bonnefon QWARN("Starting stage 3"); 2967d862d7eSNicolas Bonnefon 2977ab70cd2SNicolas Bonnefon // Add a couple more lines, including the end of the unfinished one. 2987ab70cd2SNicolas Bonnefon if ( file.open( QIODevice::Append ) ) { 2997ab70cd2SNicolas Bonnefon file.write( partial_line_end, qstrlen( partial_line_end ) ); 3007ab70cd2SNicolas Bonnefon for (int i = 0; i < 20; i++) { 3017ab70cd2SNicolas Bonnefon snprintf(newLine, 89, sl_format, i); 3027ab70cd2SNicolas Bonnefon file.write( newLine, qstrlen(newLine) ); 3037ab70cd2SNicolas Bonnefon } 3047ab70cd2SNicolas Bonnefon // To test the edge case when the final line is not complete and not matching 3057ab70cd2SNicolas Bonnefon file.write( partial_nonmatching_line_begin, 3067ab70cd2SNicolas Bonnefon qstrlen( partial_nonmatching_line_begin ) ); 3077ab70cd2SNicolas Bonnefon } 3087ab70cd2SNicolas Bonnefon file.close(); 3097ab70cd2SNicolas Bonnefon 3100b28d87cSNicolas Bonnefon // Let the system do the update 3110b28d87cSNicolas Bonnefon waitLoadingFinished(); 3120b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 3137ab70cd2SNicolas Bonnefon 3140b28d87cSNicolas Bonnefon // Start an update search 3150b28d87cSNicolas Bonnefon filteredData_->updateSearch(); 3160b28d87cSNicolas Bonnefon 3170b28d87cSNicolas Bonnefon for ( int i = 0; i < 2; i++ ) { 3180b28d87cSNicolas Bonnefon waitSearchProgressed(); 3190b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 3200b28d87cSNicolas Bonnefon } 3217ab70cd2SNicolas Bonnefon 3227ab70cd2SNicolas Bonnefon // Check the result 3230b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), 5022LL ); 3240b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 26LL ); 3257ab70cd2SNicolas Bonnefon 3267d862d7eSNicolas Bonnefon QWARN("Starting stage 4"); 3277d862d7eSNicolas Bonnefon 3287ab70cd2SNicolas Bonnefon // Now test the case where a match is found at the end of an updated line. 3297ab70cd2SNicolas Bonnefon if ( file.open( QIODevice::Append ) ) { 3307ab70cd2SNicolas Bonnefon file.write( partial_line_end, qstrlen( partial_line_end ) ); 3317ab70cd2SNicolas Bonnefon for (int i = 0; i < 20; i++) { 3327ab70cd2SNicolas Bonnefon snprintf(newLine, 89, sl_format, i); 3337ab70cd2SNicolas Bonnefon file.write( newLine, qstrlen(newLine) ); 3347ab70cd2SNicolas Bonnefon } 3357ab70cd2SNicolas Bonnefon } 3367ab70cd2SNicolas Bonnefon file.close(); 3377ab70cd2SNicolas Bonnefon 3380b28d87cSNicolas Bonnefon // Let the system do the update 3390b28d87cSNicolas Bonnefon waitLoadingFinished(); 3400b28d87cSNicolas Bonnefon signalLoadingFinishedRead(); 3417ab70cd2SNicolas Bonnefon 3420b28d87cSNicolas Bonnefon // Start an update search 3430b28d87cSNicolas Bonnefon filteredData_->updateSearch(); 3440b28d87cSNicolas Bonnefon 3450b28d87cSNicolas Bonnefon for ( int i = 0; i < 2; i++ ) { 3460b28d87cSNicolas Bonnefon waitSearchProgressed(); 3470b28d87cSNicolas Bonnefon signalSearchProgressedRead(); 3480b28d87cSNicolas Bonnefon } 3497ab70cd2SNicolas Bonnefon 3507ab70cd2SNicolas Bonnefon // Check the result 3510b28d87cSNicolas Bonnefon QCOMPARE( logData_->getNbLine(), 5042LL ); 3520b28d87cSNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 27LL ); 3530b28d87cSNicolas Bonnefon 3540b28d87cSNicolas Bonnefon QApplication::quit(); 355ba40a297SNicolas Bonnefon } 356ba40a297SNicolas Bonnefon 35764c49544SNicolas Bonnefon void TestLogFilteredData::marks() 35864c49544SNicolas Bonnefon { 35964c49544SNicolas Bonnefon logData_ = new LogData(); 36064c49544SNicolas Bonnefon 36164c49544SNicolas Bonnefon // Register for notification file is loaded 36264c49544SNicolas Bonnefon connect( logData_, SIGNAL( loadingFinished( bool ) ), 36364c49544SNicolas Bonnefon this, SLOT( loadingFinished() ) ); 36464c49544SNicolas Bonnefon 36564c49544SNicolas Bonnefon filteredData_ = logData_->getNewFilteredData(); 36664c49544SNicolas Bonnefon connect( filteredData_, SIGNAL( searchProgressed( int, int ) ), 36764c49544SNicolas Bonnefon this, SLOT( searchProgressed( int, int ) ) ); 36864c49544SNicolas Bonnefon 36964c49544SNicolas Bonnefon QFuture<void> future = QtConcurrent::run(this, &TestLogFilteredData::marksTest); 37064c49544SNicolas Bonnefon 37164c49544SNicolas Bonnefon QApplication::exec(); 37264c49544SNicolas Bonnefon 37364c49544SNicolas Bonnefon disconnect( filteredData_, 0 ); 37464c49544SNicolas Bonnefon disconnect( logData_, 0 ); 37564c49544SNicolas Bonnefon 37664c49544SNicolas Bonnefon delete filteredData_; 37764c49544SNicolas Bonnefon delete logData_; 37864c49544SNicolas Bonnefon } 37964c49544SNicolas Bonnefon 38064c49544SNicolas Bonnefon void TestLogFilteredData::marksTest() 38164c49544SNicolas Bonnefon { 38264c49544SNicolas Bonnefon // First load the tests file 38364c49544SNicolas Bonnefon logData_->attachFile( TMPDIR "/smalllog.txt" ); 38464c49544SNicolas Bonnefon // Wait for the loading to be done 38564c49544SNicolas Bonnefon waitLoadingFinished(); 38664c49544SNicolas Bonnefon QCOMPARE( logData_->getNbLine(), SL_NB_LINES ); 38764c49544SNicolas Bonnefon signalLoadingFinishedRead(); 38864c49544SNicolas Bonnefon 38964c49544SNicolas Bonnefon // First check no line is marked 39064c49544SNicolas Bonnefon for ( int i = 0; i < SL_NB_LINES; i++ ) 39164c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( i ) == false ); 39264c49544SNicolas Bonnefon 39364c49544SNicolas Bonnefon // Try to create some "out of limit" marks 39464c49544SNicolas Bonnefon filteredData_->addMark( -10 ); 39564c49544SNicolas Bonnefon filteredData_->addMark( SL_NB_LINES + 25 ); 39664c49544SNicolas Bonnefon 39764c49544SNicolas Bonnefon // Check no line is marked still 39864c49544SNicolas Bonnefon for ( int i = 0; i < SL_NB_LINES; i++ ) 39964c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( i ) == false ); 40064c49544SNicolas Bonnefon 40164c49544SNicolas Bonnefon // Create a couple of unnamed marks 40264c49544SNicolas Bonnefon filteredData_->addMark( 10 ); 403*a1e4ce92SNicolas Bonnefon filteredData_->addMark( 44 ); // This one will also be a match 40464c49544SNicolas Bonnefon filteredData_->addMark( 25 ); 40564c49544SNicolas Bonnefon 40664c49544SNicolas Bonnefon // Check they are marked 40764c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( 10 ) ); 40864c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( 25 ) ); 409*a1e4ce92SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( 44 ) ); 41064c49544SNicolas Bonnefon 41164c49544SNicolas Bonnefon // But others are not 41264c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( 15 ) == false ); 41364c49544SNicolas Bonnefon QVERIFY( filteredData_->isLineMarked( 20 ) == false ); 41464c49544SNicolas Bonnefon 415*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 3LL ); 41664c49544SNicolas Bonnefon 41764c49544SNicolas Bonnefon // Performs a search 41864c49544SNicolas Bonnefon QSignalSpy progressSpy( filteredData_, 41964c49544SNicolas Bonnefon SIGNAL( searchProgressed( int, int ) ) ); 42064c49544SNicolas Bonnefon filteredData_->runSearch( QRegExp( "0000.4" ) ); 42164c49544SNicolas Bonnefon 42264c49544SNicolas Bonnefon for ( int i = 0; i < 1; i++ ) { 42364c49544SNicolas Bonnefon waitSearchProgressed(); 42464c49544SNicolas Bonnefon signalSearchProgressedRead(); 42564c49544SNicolas Bonnefon } 42664c49544SNicolas Bonnefon 42764c49544SNicolas Bonnefon // We should have the result of the search and the marks 42864c49544SNicolas Bonnefon waitSearchProgressed(); 42964c49544SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 12LL ); 43064c49544SNicolas Bonnefon signalSearchProgressedRead(); 43164c49544SNicolas Bonnefon 432*a1e4ce92SNicolas Bonnefon QString startline = "LOGDATA is a part of glogg, we are going to test it thoroughly, this is line "; 433*a1e4ce92SNicolas Bonnefon 434*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(0), startline + "000004" ); 435*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(1), startline + "000010" ); 436*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(2), startline + "000014" ); 437*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(3), startline + "000024" ); 438*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(4), startline + "000025" ); 439*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(5), startline + "000034" ); 440*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(6), startline + "000044" ); 441*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(7), startline + "000054" ); 442*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(8), startline + "000064" ); 443*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(9), startline + "000074" ); 444*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(10), startline + "000084" ); 445*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(11), startline + "000094" ); 446*a1e4ce92SNicolas Bonnefon 447*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MatchesOnly ); 448*a1e4ce92SNicolas Bonnefon 449*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 10LL ); 450*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(0), startline + "000004" ); 451*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(1), startline + "000014" ); 452*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(2), startline + "000024" ); 453*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(3), startline + "000034" ); 454*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(4), startline + "000044" ); 455*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(5), startline + "000054" ); 456*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(6), startline + "000064" ); 457*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(7), startline + "000074" ); 458*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(8), startline + "000084" ); 459*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(9), startline + "000094" ); 460*a1e4ce92SNicolas Bonnefon 461*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MarksOnly ); 462*a1e4ce92SNicolas Bonnefon 463*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 3LL ); 464*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(0), startline + "000010" ); 465*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(1), startline + "000025" ); 466*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getLineString(2), startline + "000044" ); 467*a1e4ce92SNicolas Bonnefon 468*a1e4ce92SNicolas Bonnefon QApplication::quit(); 469*a1e4ce92SNicolas Bonnefon } 470*a1e4ce92SNicolas Bonnefon 471*a1e4ce92SNicolas Bonnefon void TestLogFilteredData::lineLength() 472*a1e4ce92SNicolas Bonnefon { 473*a1e4ce92SNicolas Bonnefon logData_ = new LogData(); 474*a1e4ce92SNicolas Bonnefon 475*a1e4ce92SNicolas Bonnefon // Register for notification file is loaded 476*a1e4ce92SNicolas Bonnefon connect( logData_, SIGNAL( loadingFinished( bool ) ), 477*a1e4ce92SNicolas Bonnefon this, SLOT( loadingFinished() ) ); 478*a1e4ce92SNicolas Bonnefon 479*a1e4ce92SNicolas Bonnefon filteredData_ = logData_->getNewFilteredData(); 480*a1e4ce92SNicolas Bonnefon connect( filteredData_, SIGNAL( searchProgressed( int, int ) ), 481*a1e4ce92SNicolas Bonnefon this, SLOT( searchProgressed( int, int ) ) ); 482*a1e4ce92SNicolas Bonnefon 483*a1e4ce92SNicolas Bonnefon QFuture<void> future = QtConcurrent::run(this, &TestLogFilteredData::lineLengthTest); 484*a1e4ce92SNicolas Bonnefon 485*a1e4ce92SNicolas Bonnefon QApplication::exec(); 486*a1e4ce92SNicolas Bonnefon 487*a1e4ce92SNicolas Bonnefon disconnect( filteredData_, 0 ); 488*a1e4ce92SNicolas Bonnefon disconnect( logData_, 0 ); 489*a1e4ce92SNicolas Bonnefon 490*a1e4ce92SNicolas Bonnefon delete filteredData_; 491*a1e4ce92SNicolas Bonnefon delete logData_; 492*a1e4ce92SNicolas Bonnefon } 493*a1e4ce92SNicolas Bonnefon 494*a1e4ce92SNicolas Bonnefon void TestLogFilteredData::lineLengthTest() 495*a1e4ce92SNicolas Bonnefon { 496*a1e4ce92SNicolas Bonnefon // Line length tests 497*a1e4ce92SNicolas Bonnefon 498*a1e4ce92SNicolas Bonnefon logData_->attachFile( TMPDIR "/length_test.txt" ); 499*a1e4ce92SNicolas Bonnefon // Wait for the loading to be done 500*a1e4ce92SNicolas Bonnefon waitLoadingFinished(); 501*a1e4ce92SNicolas Bonnefon QCOMPARE( logData_->getNbLine(), 4LL ); 502*a1e4ce92SNicolas Bonnefon signalLoadingFinishedRead(); 503*a1e4ce92SNicolas Bonnefon 504*a1e4ce92SNicolas Bonnefon // Performs a search (the two middle lines matche) 505*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MatchesOnly ); 506*a1e4ce92SNicolas Bonnefon filteredData_->runSearch( QRegExp( "longer" ) ); 507*a1e4ce92SNicolas Bonnefon 508*a1e4ce92SNicolas Bonnefon std::pair<int,int> progress; 509*a1e4ce92SNicolas Bonnefon do { 510*a1e4ce92SNicolas Bonnefon progress = waitSearchProgressed(); 511*a1e4ce92SNicolas Bonnefon signalSearchProgressedRead(); 512*a1e4ce92SNicolas Bonnefon QWARN("progress"); 513*a1e4ce92SNicolas Bonnefon } while ( progress.second < 100 ); 514*a1e4ce92SNicolas Bonnefon 515*a1e4ce92SNicolas Bonnefon filteredData_->addMark( 3 ); 516*a1e4ce92SNicolas Bonnefon 517*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 2LL ); 518*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 40 ); 519*a1e4ce92SNicolas Bonnefon 520*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MarksAndMatches ); 521*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 3LL ); 522*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 103 ); 523*a1e4ce92SNicolas Bonnefon 524*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MarksOnly ); 525*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 1LL ); 526*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 103 ); 527*a1e4ce92SNicolas Bonnefon 528*a1e4ce92SNicolas Bonnefon filteredData_->addMark( 0 ); 529*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 2LL ); 530*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 103 ); 531*a1e4ce92SNicolas Bonnefon filteredData_->deleteMark( 3 ); 532*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getNbLine(), 1LL ); 533*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 27 ); 534*a1e4ce92SNicolas Bonnefon 535*a1e4ce92SNicolas Bonnefon filteredData_->setVisibility( LogFilteredData::MarksAndMatches ); 536*a1e4ce92SNicolas Bonnefon QCOMPARE( filteredData_->getMaxLength(), 40 ); 537*a1e4ce92SNicolas Bonnefon 53864c49544SNicolas Bonnefon QApplication::quit(); 53964c49544SNicolas Bonnefon } 54064c49544SNicolas Bonnefon 541f35c72b9SNicolas Bonnefon // 542f35c72b9SNicolas Bonnefon // Private functions 543f35c72b9SNicolas Bonnefon // 544f35c72b9SNicolas Bonnefon void TestLogFilteredData::loadingFinished() 545f35c72b9SNicolas Bonnefon { 5460b28d87cSNicolas Bonnefon QMutexLocker locker( &loadingFinishedMutex_ ); 5470b28d87cSNicolas Bonnefon 5480b28d87cSNicolas Bonnefon QWARN("loadingFinished"); 5490b28d87cSNicolas Bonnefon loadingFinished_received_ = true; 5500b28d87cSNicolas Bonnefon loadingFinished_read_ = false; 5510b28d87cSNicolas Bonnefon 5520b28d87cSNicolas Bonnefon loadingFinishedCondition_.wakeOne(); 5530b28d87cSNicolas Bonnefon 5540b28d87cSNicolas Bonnefon // Wait for the test thread to read the signal 5550b28d87cSNicolas Bonnefon while ( ! loadingFinished_read_ ) 5560b28d87cSNicolas Bonnefon loadingFinishedCondition_.wait( locker.mutex() ); 557f35c72b9SNicolas Bonnefon } 558f35c72b9SNicolas Bonnefon 559f35c72b9SNicolas Bonnefon void TestLogFilteredData::searchProgressed( int nbMatches, int completion ) 560f35c72b9SNicolas Bonnefon { 5610b28d87cSNicolas Bonnefon QMutexLocker locker( &searchProgressedMutex_ ); 5620b28d87cSNicolas Bonnefon 5630b28d87cSNicolas Bonnefon QWARN("searchProgressed"); 5640b28d87cSNicolas Bonnefon searchProgressed_received_ = true; 5650b28d87cSNicolas Bonnefon searchProgressed_read_ = false; 5660b28d87cSNicolas Bonnefon 5670b28d87cSNicolas Bonnefon searchLastMatches_ = nbMatches; 5680b28d87cSNicolas Bonnefon searchLastProgress_ = completion; 5690b28d87cSNicolas Bonnefon 5700b28d87cSNicolas Bonnefon searchProgressedCondition_.wakeOne(); 5710b28d87cSNicolas Bonnefon 5720b28d87cSNicolas Bonnefon // Wait for the test thread to read the signal 5730b28d87cSNicolas Bonnefon while ( ! searchProgressed_read_ ) 5740b28d87cSNicolas Bonnefon searchProgressedCondition_.wait( locker.mutex() ); 5750b28d87cSNicolas Bonnefon } 5760b28d87cSNicolas Bonnefon 5770b28d87cSNicolas Bonnefon std::pair<int,int> TestLogFilteredData::waitSearchProgressed() 5780b28d87cSNicolas Bonnefon { 5790b28d87cSNicolas Bonnefon QMutexLocker locker( &searchProgressedMutex_ ); 5800b28d87cSNicolas Bonnefon 5810b28d87cSNicolas Bonnefon while ( ! searchProgressed_received_ ) 5820b28d87cSNicolas Bonnefon searchProgressedCondition_.wait( locker.mutex() ); 5830b28d87cSNicolas Bonnefon 5840b28d87cSNicolas Bonnefon QWARN("searchProgressed Received"); 5850b28d87cSNicolas Bonnefon 5860b28d87cSNicolas Bonnefon return std::pair<int,int>(searchLastMatches_, searchLastProgress_); 5870b28d87cSNicolas Bonnefon } 5880b28d87cSNicolas Bonnefon 5890b28d87cSNicolas Bonnefon void TestLogFilteredData::waitLoadingFinished() 5900b28d87cSNicolas Bonnefon { 5910b28d87cSNicolas Bonnefon QMutexLocker locker( &loadingFinishedMutex_ ); 5920b28d87cSNicolas Bonnefon 5930b28d87cSNicolas Bonnefon while ( ! loadingFinished_received_ ) 5940b28d87cSNicolas Bonnefon loadingFinishedCondition_.wait( locker.mutex() ); 5950b28d87cSNicolas Bonnefon 5960b28d87cSNicolas Bonnefon QWARN("loadingFinished Received"); 5970b28d87cSNicolas Bonnefon } 5980b28d87cSNicolas Bonnefon 5990b28d87cSNicolas Bonnefon void TestLogFilteredData::signalSearchProgressedRead() 6000b28d87cSNicolas Bonnefon { 6010b28d87cSNicolas Bonnefon QMutexLocker locker( &searchProgressedMutex_ ); 6020b28d87cSNicolas Bonnefon 6030b28d87cSNicolas Bonnefon searchProgressed_received_ = false; 6040b28d87cSNicolas Bonnefon searchProgressed_read_ = true; 6050b28d87cSNicolas Bonnefon searchProgressedCondition_.wakeOne(); 6060b28d87cSNicolas Bonnefon } 6070b28d87cSNicolas Bonnefon 6080b28d87cSNicolas Bonnefon void TestLogFilteredData::signalLoadingFinishedRead() 6090b28d87cSNicolas Bonnefon { 6100b28d87cSNicolas Bonnefon QMutexLocker locker( &loadingFinishedMutex_ ); 6110b28d87cSNicolas Bonnefon 6120b28d87cSNicolas Bonnefon loadingFinished_received_ = false; 6130b28d87cSNicolas Bonnefon loadingFinished_read_ = true; 6140b28d87cSNicolas Bonnefon loadingFinishedCondition_.wakeOne(); 615f35c72b9SNicolas Bonnefon } 616f35c72b9SNicolas Bonnefon 617f35c72b9SNicolas Bonnefon bool TestLogFilteredData::generateDataFiles() 618f35c72b9SNicolas Bonnefon { 619f35c72b9SNicolas Bonnefon char newLine[90]; 620f35c72b9SNicolas Bonnefon 621f35c72b9SNicolas Bonnefon QFile file( TMPDIR "/mediumlog.txt" ); 622f35c72b9SNicolas Bonnefon if ( file.open( QIODevice::WriteOnly ) ) { 623f35c72b9SNicolas Bonnefon for (int i = 0; i < ML_NB_LINES; i++) { 624f35c72b9SNicolas Bonnefon snprintf(newLine, 89, ml_format, i); 625f35c72b9SNicolas Bonnefon file.write( newLine, qstrlen(newLine) ); 626f35c72b9SNicolas Bonnefon } 627f35c72b9SNicolas Bonnefon } 628f35c72b9SNicolas Bonnefon else { 629f35c72b9SNicolas Bonnefon return false; 630f35c72b9SNicolas Bonnefon } 631f35c72b9SNicolas Bonnefon file.close(); 632f35c72b9SNicolas Bonnefon 633f35c72b9SNicolas Bonnefon file.setFileName( TMPDIR "/smalllog.txt" ); 634f35c72b9SNicolas Bonnefon if ( file.open( QIODevice::WriteOnly ) ) { 635f35c72b9SNicolas Bonnefon for (int i = 0; i < SL_NB_LINES; i++) { 636f35c72b9SNicolas Bonnefon snprintf(newLine, 89, sl_format, i); 637f35c72b9SNicolas Bonnefon file.write( newLine, qstrlen(newLine) ); 638f35c72b9SNicolas Bonnefon } 639f35c72b9SNicolas Bonnefon } 640f35c72b9SNicolas Bonnefon else { 641f35c72b9SNicolas Bonnefon return false; 642f35c72b9SNicolas Bonnefon } 643f35c72b9SNicolas Bonnefon file.close(); 644f35c72b9SNicolas Bonnefon 645*a1e4ce92SNicolas Bonnefon file.setFileName( TMPDIR "/length_test.txt" ); 646*a1e4ce92SNicolas Bonnefon if ( file.open( QIODevice::WriteOnly ) ) { 647*a1e4ce92SNicolas Bonnefon file.write( "This line is 28 characters.\n" ); 648*a1e4ce92SNicolas Bonnefon file.write( "This line is longer: 36 characters.\n" ); 649*a1e4ce92SNicolas Bonnefon file.write( "This line is even longer: 41 characters.\n" ); 650*a1e4ce92SNicolas Bonnefon file.write( "This line is very long, it's actually hard to count but it is\ 651*a1e4ce92SNicolas Bonnefon probably something around 102 characters.\n" ); 652*a1e4ce92SNicolas Bonnefon } 653*a1e4ce92SNicolas Bonnefon file.close(); 654*a1e4ce92SNicolas Bonnefon 655f35c72b9SNicolas Bonnefon return true; 656f35c72b9SNicolas Bonnefon } 657