20#include <boost/test/unit_test.hpp>
30#include <wx/filename.h>
31#include <wx/stdpaths.h>
32#include <wx/stopwatch.h>
48wxString makeTempTargetPath(
const wxString& aTag )
50 wxString tempDir = wxFileName::GetTempDir();
51 wxString leaf = wxString::Format( wxT(
"kicad-atomicsave-%s-%ld" ), aTag,
52 static_cast<long>( wxGetLocalTimeMillis().GetValue() ) );
53 return tempDir + wxFileName::GetPathSeparator() + leaf;
57void writeFileContents(
const wxString& aPath,
const std::string& aContent )
59 wxFFile fp( aPath, wxT(
"wb" ) );
62 if( !aContent.empty() )
63 BOOST_REQUIRE( fp.Write( aContent.data(), aContent.size() ) == aContent.size() );
69std::string readFileContents(
const wxString& aPath )
71 wxFFile fp( aPath, wxT(
"rb" ) );
78 std::string out = std::string( buf.mb_str( wxConvUTF8 ) );
86unsigned countSiblingTemps(
const wxString& aTargetPath )
88 wxFileName fn( aTargetPath );
89 wxString dir = fn.GetPath();
90 wxString pattern = fn.GetFullName() + wxT(
".kicad-save-*" );
91 wxArrayString matches;
92 wxDir::GetAllFiles( dir, &matches, pattern, wxDIR_FILES );
93 return matches.GetCount();
104 wxString target = makeTempTargetPath( wxT(
"happy" ) );
108 f.
Print( 0,
"(kicad_test (content \"hello\"))\n" );
113 std::string
actual = readFileContents( target );
116 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
118 wxRemoveFile( target );
127 wxString target = makeTempTargetPath( wxT(
"unwind" ) );
128 const std::string original =
"(original \"do not lose me\")\n";
129 writeFileContents( target, original );
134 f.
Print( 0,
"(partial " );
138 throw std::runtime_error(
"simulated serializer failure" );
140 std::runtime_error );
143 BOOST_REQUIRE_EQUAL( readFileContents( target ), original );
144 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
146 wxRemoveFile( target );
154 wxString target = makeTempTargetPath( wxT(
"implicit" ) );
158 f.
Print( 0,
"(implicit_commit ok)\n" );
162 std::string
actual = readFileContents( target );
164 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
166 wxRemoveFile( target );
174 wxString target = makeTempTargetPath( wxT(
"stream" ) );
175 const std::string original =
"original streaming content\n";
176 writeFileContents( target, original );
181 f.
Print( 0,
"partial write before the crash " );
182 throw std::runtime_error(
"simulated exporter failure" );
184 std::runtime_error );
187 BOOST_REQUIRE_EQUAL( readFileContents( target ), original );
188 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
190 wxRemoveFile( target );
196 wxString target = makeTempTargetPath( wxT(
"atomicbuf" ) );
197 const std::string payload =
"{\"setting\":42}\n";
204 BOOST_REQUIRE_EQUAL( readFileContents( target ), payload );
205 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
207 wxRemoveFile( target );
215 wxString target = makeTempTargetPath( wxT(
"overwrite" ) );
216 const std::string original =
"unchanged\n";
217 writeFileContents( target, original );
222 wxString bogus = target + wxT(
"/subdir/cannot-create" );
229 BOOST_REQUIRE_EQUAL( readFileContents( target ), original );
231 wxRemoveFile( target );
238 wxString target = makeTempTargetPath( wxT(
"commitfail-explicit" ) );
240 BOOST_REQUIRE( wxFileName::Mkdir( target, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
247 f.
Print( 0,
"(doomed save)\n" );
255 BOOST_REQUIRE_MESSAGE( threw,
"Finish() must throw IO_ERROR when atomic commit fails" );
257 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
259 wxFileName::Rmdir( target );
265 wxString target = makeTempTargetPath( wxT(
"commitfail-stream" ) );
267 BOOST_REQUIRE( wxFileName::Mkdir( target, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
274 f.
Print( 0,
"doomed streaming save\n" );
282 BOOST_REQUIRE_MESSAGE( threw,
"Finish() must throw IO_ERROR when atomic commit fails" );
284 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
286 wxFileName::Rmdir( target );
295 model.SetEmptyLayout();
297 wxString target = makeTempTargetPath( wxT(
"wks-commitfail" ) );
298 BOOST_REQUIRE( wxFileName::Mkdir( target, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
302 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
304 wxFileName::Rmdir( target );
313 wxString target = makeTempTargetPath( wxT(
"commitfail-implicit" ) );
315 BOOST_REQUIRE( wxFileName::Mkdir( target, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
319 f.
Print( 0,
"(implicit doomed)\n" );
323 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
325 wxFileName::Rmdir( target );
332 wxString target = makeTempTargetPath( wxT(
"newtarget" ) );
337 f.
Print( 0,
"(new_file content)\n" );
342 std::string
actual = readFileContents( target );
344 BOOST_REQUIRE_EQUAL( countSiblingTemps( target ), 0u );
346 wxRemoveFile( target );
350#if !defined( _WIN32 )
357 wxString target = makeTempTargetPath( wxT(
"mode" ) );
358 const std::string original =
"original\n";
359 writeFileContents( target, original );
361 BOOST_REQUIRE_EQUAL( chmod( target.fn_str(), 0400 ), 0 );
363 const std::string payload =
"replacement\n";
370 BOOST_REQUIRE_EQUAL( stat( target.fn_str(), &st ), 0 );
371 BOOST_REQUIRE_EQUAL( st.st_mode & 0777, 0400 );
372 BOOST_REQUIRE_EQUAL( readFileContents( target ), payload );
374 chmod( target.fn_str(), 0600 );
375 wxRemoveFile( target );
384 wxString referent = makeTempTargetPath( wxT(
"symref" ) );
385 wxString linkPath = makeTempTargetPath( wxT(
"symlink" ) );
386 const std::string original =
"referent original\n";
387 writeFileContents( referent, original );
389 BOOST_REQUIRE_EQUAL( symlink( referent.fn_str(), linkPath.fn_str() ), 0 );
391 const std::string payload =
"replacement via symlink\n";
398 BOOST_REQUIRE_EQUAL( lstat( linkPath.fn_str(), &st ), 0 );
402 BOOST_REQUIRE_EQUAL( readFileContents( referent ), payload );
404 wxRemoveFile( linkPath );
405 wxRemoveFile( referent );
415 wxString target = makeTempTargetPath( wxT(
"failrestore" ) );
416 const std::string original =
"original\n";
417 writeFileContents( target, original );
418 BOOST_REQUIRE_EQUAL( chmod( target.fn_str(), 0400 ), 0 );
423 wxString bogus = target + wxT(
"/cannot-create" );
428 BOOST_REQUIRE_EQUAL( stat( target.fn_str(), &st ), 0 );
429 BOOST_REQUIRE_EQUAL( st.st_mode & 0777, 0400 );
430 BOOST_REQUIRE_EQUAL( readFileContents( target ), original );
432 chmod( target.fn_str(), 0600 );
433 wxRemoveFile( target );
442 wxString target = makeTempTargetPath( wxT(
"winattrs" ) );
443 const std::string original =
"original\n";
444 writeFileContents( target, original );
447 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN ) );
449 const std::string payload =
"replacement\n";
455 DWORD attrs = GetFileAttributesW( target.wc_str() );
459 BOOST_REQUIRE_EQUAL( readFileContents( target ), payload );
461 SetFileAttributesW( target.wc_str(), FILE_ATTRIBUTE_NORMAL );
462 wxRemoveFile( target );
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(PrettifiedFormatter_HappyPath)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()