29#include <wx/filename.h>
37namespace fs = std::filesystem;
45 m_tempDir = fs::temp_directory_path() /
"kicad_project_file_test";
64 fs::path projectPath = m_tempDir /
"api_kitchen_sink.kicad_pro";
73 project.m_IP2581Bom.sections = wxString();
93 fs::path oldProjectDir = m_tempDir /
"old_project";
94 fs::path newProjectDir = m_tempDir /
"new_project";
95 fs::create_directories( oldProjectDir );
96 fs::create_directories( newProjectDir );
98 wxString oldProjectPath = wxString( oldProjectDir.string() ) + wxFileName::GetPathSeparator()
106 sheetInfo.
name = wxS(
"old_project" );
107 sheetInfo.
filename = wxS(
"old_project.kicad_sch" );
114 customSheet.
name = wxS(
"CustomSheet" );
115 customSheet.
filename = wxS(
"custom_sheet.kicad_sch" );
120 projectFile.
SaveAs( wxString( newProjectDir.string() ), wxS(
"new_project" ) );
123 const std::vector<TOP_LEVEL_SHEET_INFO>& sheets = projectFile.
GetTopLevelSheets();
125 BOOST_REQUIRE_EQUAL( sheets.size(), 2 );
152 fs::path projectDir = m_tempDir /
"my_project";
153 fs::create_directories( projectDir );
156 std::string proContent = R
"({
158 "filename": "my_project.kicad_pro",
162 "top_level_sheets": [
164 "uuid": "00000000-0000-0000-0000-000000000000",
166 "filename": "default.kicad_sch"
172 fs::path proPath = projectDir / "my_project.kicad_pro";
173 std::ofstream proFile( proPath );
174 proFile << proContent;
178 fs::path schPath = projectDir /
"my_project.kicad_sch";
179 std::ofstream schFile( schPath );
180 schFile <<
"(kicad_sch (version 20231120) (generator \"eeschema\") (generator_version \"9.99\")";
181 schFile <<
" (uuid \"12345678-1234-1234-1234-123456789abc\")";
182 schFile <<
" (paper \"A4\"))";
187 settingsManager.
LoadProject( wxString( proPath.string() ) );
192 const std::vector<TOP_LEVEL_SHEET_INFO>& sheets = projectFile.
GetTopLevelSheets();
194 BOOST_REQUIRE_EQUAL( sheets.size(), 1 );
209 fs::path projectDir = m_tempDir /
"valid_project";
210 fs::create_directories( projectDir );
213 std::string proContent = R
"({
215 "filename": "valid_project.kicad_pro",
219 "top_level_sheets": [
221 "uuid": "00000000-0000-0000-0000-000000000000",
222 "name": "valid_project",
223 "filename": "valid_project.kicad_sch"
229 fs::path proPath = projectDir / "valid_project.kicad_pro";
230 std::ofstream proFile( proPath );
231 proFile << proContent;
235 fs::path schPath = projectDir /
"valid_project.kicad_sch";
236 std::ofstream schFile( schPath );
237 schFile <<
"(kicad_sch (version 20231120) (generator \"eeschema\") (generator_version \"9.99\")";
238 schFile <<
" (uuid \"12345678-1234-1234-1234-123456789abc\")";
239 schFile <<
" (paper \"A4\"))";
243 settingsManager.
LoadProject( wxString( proPath.string() ) );
248 const std::vector<TOP_LEVEL_SHEET_INFO>& sheets = projectFile.
GetTopLevelSheets();
250 BOOST_REQUIRE_EQUAL( sheets.size(), 1 );
273 fs::path projectDir = m_tempDir /
"jobset_project";
274 fs::create_directories( projectDir );
276 std::string proContent = R
"({
278 "filename": "jobset_project.kicad_pro",
283 fs::path proPath = projectDir / "jobset_project.kicad_pro";
284 std::ofstream proFile( proPath );
285 proFile << proContent;
288 wxFileName absFn( wxString( proPath.string() ) );
289 absFn.MakeAbsolute();
290 wxString absPath = absFn.GetFullPath();
305 BOOST_CHECK( afterReload == heldProject );
323 fs::path projADir = m_tempDir /
"proj_a";
324 fs::path projBDir = m_tempDir /
"proj_b";
325 fs::create_directories( projADir );
326 fs::create_directories( projBDir );
331 const std::string projectName =
"shared_name";
333 auto writeProject = [&](
const fs::path& aDir )
335 std::string content =
"{\n"
337 " \"filename\": \"" + projectName +
".kicad_pro\",\n"
340 " \"schematic\": {\n"
341 " \"top_level_sheets\": [\n"
343 " \"uuid\": \"00000000-0000-0000-0000-000000000000\",\n"
344 " \"name\": \"" + projectName +
"\",\n"
345 " \"filename\": \"" + projectName +
".kicad_sch\"\n"
350 std::ofstream out( aDir / ( projectName +
".kicad_pro" ) );
354 std::ofstream sch( aDir / ( projectName +
".kicad_sch" ) );
355 sch <<
"(kicad_sch (version 20231120) (generator \"eeschema\") (generator_version \"9.99\")";
356 sch <<
" (uuid \"12345678-1234-1234-1234-123456789abc\") (paper \"A4\"))";
360 fs::path proAPath = projADir / ( projectName +
".kicad_pro" );
361 fs::path proBPath = projBDir / ( projectName +
".kicad_pro" );
362 writeProject( projADir );
363 writeProject( projBDir );
382 auto readFile = [](
const fs::path& aPath )
384 std::ifstream in( aPath );
385 std::stringstream buffer;
386 buffer << in.rdbuf();
391 std::string savedB =
readFile( proBPath );
392 BOOST_CHECK_MESSAGE( savedB.find(
"OWNER" ) != std::string::npos,
393 "unloaded project must be saved to its own directory" );
396 std::string savedA =
readFile( proAPath );
397 BOOST_CHECK_MESSAGE( savedA.find(
"OWNER" ) == std::string::npos,
398 "active project's file must not receive the unloaded project's data" );
405 auto projectPath = [&](
const std::string& aName )
407 fs::path dir = m_tempDir / aName;
408 fs::create_directories( dir );
409 return wxString( ( dir / ( aName +
".kicad_pro" ) ).
string() );
412 const wxString active = projectPath(
"z_active" );
413 const wxString passive = projectPath(
"a_passive" );
414 const wxString
next = projectPath(
"m_next" );
423 BOOST_CHECK( mgr.
GetProject( active ) ==
nullptr );
424 BOOST_CHECK( mgr.
GetProject( passive ) !=
nullptr );
440 fs::path projectDir = m_tempDir /
"unchanged_project";
441 fs::create_directories( projectDir );
443 fs::path proPath = projectDir /
"unchanged_project.kicad_pro";
448 std::ofstream seed( proPath );
449 seed << R
"({"meta":{"version":3}})";
458 auto readFile = [](
const fs::path& aPath )
460 std::ifstream in( aPath );
461 std::stringstream buffer;
462 buffer << in.rdbuf();
469 nlohmann::json js = nlohmann::json::parse(
readFile( proPath ) );
470 js[
"board"].erase(
"ipc2581" );
471 js[
"schematic"].erase(
"bus_aliases" );
473 std::ofstream out( proPath );
474 out << std::setw( 2 ) << js << std::endl;
478 std::string before =
readFile( proPath );
479 BOOST_REQUIRE( before.find(
"ipc2581" ) == std::string::npos );
480 BOOST_REQUIRE( before.find(
"bus_aliases" ) == std::string::npos );
488 BOOST_CHECK( !projectFile.
SaveToFile( wxString( projectDir.string() ) ) );
500 nlohmann::json saved = nlohmann::json::parse(
readFile( proPath ) );
501 BOOST_CHECK( saved[
"schematic"][
"bus_aliases"].is_object() );
502 BOOST_CHECK( saved[
"schematic"][
"bus_aliases"].
empty() );
508 const fs::path projectPath = m_tempDir /
"aliases.kicad_pro";
509 const nlohmann::json aliases = { {
"USB", {
"D+",
"D-" } } };
512 std::ofstream output( projectPath );
513 output << nlohmann::json( { {
"meta", { {
"version", 3 } } },
514 {
"schematic", { {
"bus_aliases", aliases } } } } ).
dump( 2 );
523 BOOST_REQUIRE_EQUAL(
project.m_BusAliases.size(), 1 );
524 BOOST_CHECK(
project.m_BusAliases.at(
"USB" ) == std::vector<wxString>( {
"D+",
"D-" } ) );
526 std::ifstream input( projectPath );
527 const nlohmann::json saved = nlohmann::json::parse( input );
529 BOOST_CHECK( saved[
"schematic"][
"bus_aliases"] == aliases );
535 const fs::path legacyPath = m_tempDir /
"field_names.pro";
536 const fs::path projectPath = m_tempDir /
"field_names.kicad_pro";
539 std::ofstream output( legacyPath );
540 output <<
"[schematic_editor]\n"
541 "FieldNameTemplates=(templatefields (field (name \"Manufacturer\") visible url))\n";
547 const auto& fields =
project.m_TemplateFieldNames.GetTemplateFieldNames( TEMPLATES::SCOPE::PROJECT );
548 BOOST_REQUIRE_EQUAL( fields.size(), 1 );
550 BOOST_CHECK( fields[0].m_Visible );
551 BOOST_CHECK( fields[0].m_URL );
553 const nlohmann::json saved = nlohmann::json::parse(
project.FormatAsString() );
554 const auto& fieldNames = saved[
"schematic"][
"drawing"][
"field_names"];
556 BOOST_REQUIRE_EQUAL( fieldNames.size(), 1 );
563 const fs::path projectPath = m_tempDir /
"field_names.kicad_pro";
564 nlohmann::json projectJson = { {
"meta", { {
"version", 4 } } } };
565 projectJson[
"schematic"][
"drawing"][
"field_names"] =
566 nlohmann::json::array( { { {
"name",
"Manufacturer" }, {
"visible",
true }, {
"url",
false } } } );
568 auto writeProject = [&]()
570 std::ofstream output( projectPath );
571 output << projectJson.dump( 2 );
578 BOOST_REQUIRE_EQUAL(
project.m_TemplateFieldNames.GetTemplateFieldNames( TEMPLATES::SCOPE::PROJECT ).size(), 1 );
580 projectJson[
"schematic"][
"drawing"][
"field_names"] = nlohmann::json::array();
584 BOOST_CHECK(
project.m_TemplateFieldNames.GetTemplateFieldNames( TEMPLATES::SCOPE::PROJECT ).empty() );
std::optional< nlohmann::json > GetJson(const std::string &aPath) const
Fetches a JSON object that is a subset of this JSON_SETTINGS object, using a path of the form "key1....
~PROJECT_FILE_TEST_FIXTURE()
PROJECT_FILE_TEST_FIXTURE()
The backing store for a PROJECT, in JSON format.
std::map< wxString, wxString > m_TextVars
bool m_BusAliasesDefined
An explicit alias table was loaded or set, including a deliberately empty table.
struct IP2581_BOM m_IP2581Bom
Layer pair list for the board.
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
std::vector< TOP_LEVEL_SHEET_INFO > & GetTopLevelSheets()
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
Container for project specific data.
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
virtual PROJECT_FILE & GetProjectFile() const
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieve a loaded project by name.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Save, unload and unregister the given PROJECT.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
static bool empty(const wxTextEntryBase *aCtrl)
static const std::string ProjectFileExtension
std::string GetTestDataRootDir()
static bool readFile(const wxString &aFileName, wxString &aOut, size_t aLimit=0)
Read a file into aOut.
std::optional< wxString > sections
Table 4 section key, unset when the mode picks the sections.
Information about a top-level schematic sheet.
KIID uuid
Unique identifier for the sheet.
wxString name
Display name for the sheet.
wxString filename
Relative path to the sheet file.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(Ipc2581ExplicitEmptySectionsRoundTrips)
BOOST_CHECK_EQUAL(result, "25.4")
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
Definition of file extensions used in Kicad.