diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index 1e203fd754..a6a4c84e6d 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -3099,8 +3099,26 @@ PCB_REFERENCE_IMAGE* PCB_PARSER::parsePCB_REFERENCE_IMAGE( BOARD_ITEM* aParent ) break; } + case T_locked: + { + // This has only ever been (locked yes) format + const bool locked = parseBool(); + bitmap->SetLocked( locked ); + + NeedRIGHT(); + break; + } + + case T_uuid: + { + NextTok(); + const_cast( bitmap->m_Uuid ) = CurStrToKIID(); + NeedRIGHT(); + break; + } + default: - Expecting( "at, layer, scale, data" ); + Expecting( "at, layer, scale, data, locked or uuid" ); } } diff --git a/pcbnew/plugins/kicad/pcb_plugin.cpp b/pcbnew/plugins/kicad/pcb_plugin.cpp index 15bad97567..1d0df53ecc 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.cpp +++ b/pcbnew/plugins/kicad/pcb_plugin.cpp @@ -1041,9 +1041,10 @@ void PCB_PLUGIN::format( const PCB_REFERENCE_IMAGE* aBitmap, int aNestLevel ) co formatLayer( aBitmap->GetLayer() ); if( aBitmap->GetImage()->GetScale() != 1.0 ) - m_out->Print( 0, " (scale %g)", aBitmap->GetImage()->GetScale() ); + m_out->Print( 0, "(scale %g)", aBitmap->GetImage()->GetScale() ); - m_out->Print( 0, "\n" ); + if( const bool locked = aBitmap->IsLocked() ) + KICAD_FORMAT::FormatBool( m_out, 0, "locked", locked ); m_out->Print( aNestLevel + 1, "(data" ); @@ -1064,6 +1065,9 @@ void PCB_PLUGIN::format( const PCB_REFERENCE_IMAGE* aBitmap, int aNestLevel ) co m_out->Print( 0, "\n" ); m_out->Print( aNestLevel + 1, ")\n" ); // Closes data token. + + KICAD_FORMAT::FormatUuid( m_out, aBitmap->m_Uuid, 0 ); + m_out->Print( aNestLevel, ")\n" ); // Closes image token. } diff --git a/qa/data/pcbnew/reference_images_load_save.kicad_pcb b/qa/data/pcbnew/reference_images_load_save.kicad_pcb new file mode 100644 index 0000000000..0e31db34f1 --- /dev/null +++ b/qa/data/pcbnew/reference_images_load_save.kicad_pcb @@ -0,0 +1,283 @@ +(kicad_pcb + (version 20231212) + (generator "pcbnew") + (generator_version "7.99") + (general + (thickness 1.6) + (legacy_teardrops no) + ) + (paper "A4") + (layers + (0 "F.Cu" signal) + (31 "B.Cu" signal) + (32 "B.Adhes" user "B.Adhesive") + (33 "F.Adhes" user "F.Adhesive") + (34 "B.Paste" user) + (35 "F.Paste" user) + (36 "B.SilkS" user "B.Silkscreen") + (37 "F.SilkS" user "F.Silkscreen") + (38 "B.Mask" user) + (39 "F.Mask" user) + (40 "Dwgs.User" user "User.Drawings") + (41 "Cmts.User" user "User.Comments") + (42 "Eco1.User" user "User.Eco1") + (43 "Eco2.User" user "User.Eco2") + (44 "Edge.Cuts" user) + (45 "Margin" user) + (46 "B.CrtYd" user "B.Courtyard") + (47 "F.CrtYd" user "F.Courtyard") + (48 "B.Fab" user) + (49 "F.Fab" user) + (50 "User.1" user) + (51 "User.2" user) + (52 "User.3" user) + (53 "User.4" user) + (54 "User.5" user) + (55 "User.6" user) + (56 "User.7" user) + (57 "User.8" user) + (58 "User.9" user) + ) + (setup + (pad_to_mask_clearance 0) + (allow_soldermask_bridges_in_footprints no) + (pcbplotparams + (layerselection 0x00010fc_ffffffff) + (plot_on_all_layers_selection 0x0000000_00000000) + (disableapertmacros no) + (usegerberextensions no) + (usegerberattributes yes) + (usegerberadvancedattributes yes) + (creategerberjobfile yes) + (dashed_line_dash_ratio 12.000000) + (dashed_line_gap_ratio 3.000000) + (svgprecision 4) + (plotframeref no) + (viasonmask no) + (mode 1) + (useauxorigin no) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (pdf_front_fp_property_popups yes) + (pdf_back_fp_property_popups yes) + (dxfpolygonmode yes) + (dxfimperialunits yes) + (dxfusepcbnewfont yes) + (psnegative no) + (psa4output no) + (plotreference yes) + (plotvalue yes) + (plotfptext yes) + (plotinvisibletext no) + (sketchpadsonfab no) + (subtractmaskfromsilk no) + (outputformat 1) + (mirror no) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + (net 0 "") + (image + (at 100 46) + (layer "F.Cu") + (data "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" + "TkSuQmCC" + ) + (uuid "7dde345e-020a-4fdd-af77-588b452be5e0") + ) + (image + (at 100 65) + (layer "F.Cu") + (locked yes) + (data "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" + "TkSuQmCC" + ) + (uuid "e4fd52dd-1d89-4c43-b621-aebfc9788d5c") + ) + (image + (at 100 90) + (layer "B.Cu") + (scale 2) + (data "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" + "TkSuQmCC" + ) + (uuid "d402397e-bce0-4cae-a398-b5aeef397e87") + ) + (gr_text "Image at scale 1" + (at 97 38 0) + (layer "Cmts.User") + (uuid "11c5bcf4-add5-4b5a-8a6e-551d6cc455dc") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Locked image" + (at 97 57 0) + (layer "Cmts.User") + (uuid "ad07820b-4490-4581-87a7-7709f90e4f7e") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Image at scale 2 on B.Cu" + (at 97 76 0) + (layer "Cmts.User") + (uuid "c4b3cc49-cd2d-43d3-93e2-82f81e39ecf0") + (effects + (font + (size 1.5 1.5) + (thickness 0.3) + (bold yes) + ) + (justify left bottom) + ) + ) +) \ No newline at end of file diff --git a/qa/data/pcbnew/reference_images_load_save.kicad_pro b/qa/data/pcbnew/reference_images_load_save.kicad_pro new file mode 100644 index 0000000000..09ea57b72a --- /dev/null +++ b/qa/data/pcbnew/reference_images_load_save.kicad_pro @@ -0,0 +1,271 @@ +{ + "board": { + "3dviewports": [], + "design_settings": { + "defaults": { + "apply_defaults_to_fp_fields": false, + "apply_defaults_to_fp_shapes": false, + "apply_defaults_to_fp_text": false, + "board_outline_line_width": 0.049999999999999996, + "copper_line_width": 0.19999999999999998, + "copper_text_italic": false, + "copper_text_size_h": 1.5, + "copper_text_size_v": 1.5, + "copper_text_thickness": 0.3, + "copper_text_upright": false, + "courtyard_line_width": 0.049999999999999996, + "dimension_precision": 4, + "dimension_units": 3, + "dimensions": { + "arrow_length": 1270000, + "extension_offset": 500000, + "keep_text_aligned": true, + "suppress_zeroes": false, + "text_position": 0, + "units_format": 1 + }, + "fab_line_width": 0.09999999999999999, + "fab_text_italic": false, + "fab_text_size_h": 1.0, + "fab_text_size_v": 1.0, + "fab_text_thickness": 0.15, + "fab_text_upright": false, + "other_line_width": 0.09999999999999999, + "other_text_italic": false, + "other_text_size_h": 1.0, + "other_text_size_v": 1.0, + "other_text_thickness": 0.15, + "other_text_upright": false, + "pads": { + "drill": 0.762, + "height": 1.524, + "width": 1.524 + }, + "silk_line_width": 0.09999999999999999, + "silk_text_italic": false, + "silk_text_size_h": 1.0, + "silk_text_size_v": 1.0, + "silk_text_thickness": 0.09999999999999999, + "silk_text_upright": false, + "zones": { + "min_clearance": 0.5 + } + }, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "meta": { + "version": 2 + }, + "rule_severities": { + "annular_width": "error", + "clearance": "error", + "connection_width": "warning", + "copper_edge_clearance": "error", + "copper_sliver": "warning", + "courtyards_overlap": "error", + "diff_pair_gap_out_of_range": "error", + "diff_pair_uncoupled_length_too_long": "error", + "drill_out_of_range": "error", + "duplicate_footprints": "warning", + "extra_footprint": "warning", + "footprint": "error", + "footprint_type_mismatch": "ignore", + "hole_clearance": "error", + "hole_near_hole": "error", + "invalid_outline": "error", + "isolated_copper": "warning", + "item_on_disabled_layer": "error", + "items_not_allowed": "error", + "length_out_of_range": "error", + "lib_footprint_issues": "warning", + "lib_footprint_mismatch": "warning", + "malformed_courtyard": "error", + "microvia_drill_out_of_range": "error", + "missing_courtyard": "ignore", + "missing_footprint": "warning", + "net_conflict": "warning", + "npth_inside_courtyard": "ignore", + "padstack": "warning", + "pth_inside_courtyard": "ignore", + "shorting_items": "error", + "silk_edge_clearance": "warning", + "silk_over_copper": "warning", + "silk_overlap": "warning", + "skew_out_of_range": "error", + "solder_mask_bridge": "error", + "starved_thermal": "error", + "text_height": "warning", + "text_thickness": "warning", + "through_hole_pad_without_hole": "error", + "too_many_vias": "error", + "track_dangling": "warning", + "track_width": "error", + "tracks_crossing": "error", + "unconnected_items": "error", + "unresolved_variable": "error", + "via_dangling": "warning", + "zones_intersect": "error" + }, + "rules": { + "max_error": 0.005, + "min_clearance": 0.0, + "min_connection": 0.0, + "min_copper_edge_clearance": 0.5, + "min_hole_clearance": 0.25, + "min_hole_to_hole": 0.25, + "min_microvia_diameter": 0.19999999999999998, + "min_microvia_drill": 0.09999999999999999, + "min_resolved_spokes": 2, + "min_silk_clearance": 0.0, + "min_text_height": 0.7999999999999999, + "min_text_thickness": 0.08, + "min_through_hole_diameter": 0.3, + "min_track_width": 0.0, + "min_via_annular_width": 0.09999999999999999, + "min_via_diameter": 0.5, + "solder_mask_to_copper_clearance": 0.0, + "use_height_for_length_calcs": true + }, + "teardrop_options": [ + { + "td_onpadsmd": true, + "td_onroundshapesonly": false, + "td_ontrackend": false, + "td_onviapad": true + } + ], + "teardrop_parameters": [ + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_round_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_rect_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_track_end", + "td_width_to_size_filter_ratio": 0.9 + } + ], + "track_widths": [], + "tuning_pattern_settings": { + "diff_pair_defaults": { + "corner_radius_percentage": 100, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.1, + "single_sided": false, + "spacing": 0.6 + }, + "diff_pair_skew_defaults": { + "corner_radius_percentage": 100, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.1, + "single_sided": false, + "spacing": 0.6 + }, + "single_track_defaults": { + "corner_radius_percentage": 100, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.1, + "single_sided": false, + "spacing": 0.6 + } + }, + "via_dimensions": [], + "zones_allow_external_fillets": false + }, + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "cvpcb": { + "equivalence_files": [] + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "pcb_reference_images.kicad_pro", + "version": 1 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.2, + "via_diameter": 0.6, + "via_drill": 0.3, + "wire_width": 6 + } + ], + "meta": { + "version": 3 + }, + "net_colors": null, + "netclass_assignments": null, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "plot": "", + "pos_files": "", + "specctra_dsn": "", + "step": "", + "svg": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "legacy_lib_dir": "", + "legacy_lib_list": [] + }, + "sheets": [], + "text_variables": {} +} diff --git a/qa/pcbnew_utils/board_test_utils.cpp b/qa/pcbnew_utils/board_test_utils.cpp index 76653153b5..a71a6cdff5 100644 --- a/qa/pcbnew_utils/board_test_utils.cpp +++ b/qa/pcbnew_utils/board_test_utils.cpp @@ -26,19 +26,21 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include + +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define CHECK_ENUM_CLASS_EQUAL( L, R ) \ BOOST_CHECK_EQUAL( static_cast( L ), static_cast( R ) ) @@ -114,6 +116,49 @@ void LoadBoard( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath, } +BOARD_ITEM& RequireBoardItemWithTypeAndId( const BOARD& aBoard, KICAD_T aItemType, const KIID& aID ) +{ + BOARD_ITEM* item = aBoard.GetItem( aID ); + + BOOST_REQUIRE( item ); + BOOST_REQUIRE( item->Type() == aItemType ); + + return *item; +} + + +void LoadAndTestBoardFile( const wxString aRelativePath, bool aRoundtrip, + std::function aBoardTestFunction ) +{ + const std::string absBoardPath = + KI_TEST::GetPcbnewTestDataDir() + aRelativePath.ToStdString() + ".kicad_pcb"; + + BOOST_TEST_MESSAGE( "Loading board to test: " << absBoardPath ); + std::unique_ptr board1 = KI_TEST::ReadBoardFromFileOrStream( absBoardPath ); + + // Should load - if it doesn't we're done for + BOOST_REQUIRE( board1 ); + + BOOST_TEST_MESSAGE( "Testing loaded board" ); + aBoardTestFunction( *board1 ); + + if( aRoundtrip ) + { + const auto savePath = std::filesystem::temp_directory_path() + / ( aRelativePath.ToStdString() + ".kicad_pcb" ); + KI_TEST::DumpBoardToFile( *board1, savePath.string() ); + + std::unique_ptr board2 = KI_TEST::ReadBoardFromFileOrStream( savePath.string() ); + + // Should load again + BOOST_REQUIRE( board2 ); + + BOOST_TEST_MESSAGE( "Testing roundtripped (saved/reloaded) file" ); + aBoardTestFunction( *board2 ); + } +} + + void FillZones( BOARD* m_board ) { TOOL_MANAGER toolMgr; diff --git a/qa/pcbnew_utils/include/pcbnew_utils/board_test_utils.h b/qa/pcbnew_utils/include/pcbnew_utils/board_test_utils.h index 4c79ae0218..629d7895b1 100644 --- a/qa/pcbnew_utils/include/pcbnew_utils/board_test_utils.h +++ b/qa/pcbnew_utils/include/pcbnew_utils/board_test_utils.h @@ -27,15 +27,19 @@ #include #include -#include #include #include + +#include + #include +#include #include class BOARD; class BOARD_ITEM; class FOOTPRINT; +class KIID; class PCB_TEXT; class PCB_SHAPE; class ZONE; @@ -43,7 +47,6 @@ class PAD; class SHAPE_POLY_SET; class SETTINGS_MANAGER; - namespace KI_TEST { class DUMMY_TOOL : public TOOL_BASE @@ -173,6 +176,32 @@ private: void LoadBoard( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath, std::unique_ptr& aBoard ); +/** + * @brief Get an item from the given board with a certain type and UUID. + * + * If this doesn't exist, it's a BOOST_REQUIRE failure. + * + * @param aBoard the board to look in + * @param aItemType the required item type + * @param aID the required + * @return BOARD_ITEM& the required board item + */ +BOARD_ITEM& RequireBoardItemWithTypeAndId( const BOARD& aBoard, KICAD_T aItemType, + const KIID& aID ); + +/** + * @brief Perform "some test" on a board file loaded from the path, + * then optionally save and reload and run the test again. + * + * The roundtrip is useful to test stability of serialisation/reload. + * + * @param aRelativePath relative path of file to load + * @param aRoundtrip true to save, reload and re-test + * @param aBoardTestFunction the function that runs tests on the board + */ +void LoadAndTestBoardFile( const wxString aRelativePath, bool aRoundtrip, + std::function aBoardTestFunction ); + void FillZones( BOARD* m_board ); diff --git a/qa/tests/pcbnew/CMakeLists.txt b/qa/tests/pcbnew/CMakeLists.txt index 03ca6a45b1..f333a159f0 100644 --- a/qa/tests/pcbnew/CMakeLists.txt +++ b/qa/tests/pcbnew/CMakeLists.txt @@ -40,6 +40,7 @@ set( QA_PCBNEW_SRCS test_pad_numbering.cpp test_prettifier.cpp test_libeval_compiler.cpp + test_reference_image_load.cpp test_save_load.cpp test_tracks_cleaner.cpp test_zone_filler.cpp diff --git a/qa/tests/pcbnew/test_footprint_load_save.cpp b/qa/tests/pcbnew/test_footprint_load_save.cpp new file mode 100644 index 0000000000..2759bd76e3 --- /dev/null +++ b/qa/tests/pcbnew/test_footprint_load_save.cpp @@ -0,0 +1,102 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +struct FOOTPRINT_LOAD_TEST_FIXTURE +{ + FOOTPRINT_LOAD_TEST_FIXTURE() {} +}; + + +struct FOOTPRINT_LOAD_TEST_CASE +{ + // Which footprint this is + KIID m_footprintUuid; + bool m_expectedLocked; + VECTOR2I m_expectedPos; +}; + + +struct FOOTPRINT_LOAD_BOARD_TEST_CASE +{ + // The board to load + wxString m_boardFileRelativePath; + // List of images to check + std::vector m_imageCases; +}; + +} // namespace + +BOOST_FIXTURE_TEST_CASE( FootprintLoadSave, FOOTPRINT_LOAD_TEST_FIXTURE ) +{ + const std::vector testCases{ + { + "footprints_load_save", + { + // From top to bottom in the board file + { + "898cf321-03c7-40bb-8d78-4bc5e52986c2", + false, + { 100, 80 }, + }, + { + "0775cd70-2e84-4592-a160-456c37a8f4f6", + true, + { 100, 100 }, + }, + }, + }, + }; + + for( const FOOTPRINT_LOAD_BOARD_TEST_CASE& testCase : testCases ) + { + const auto doBoardTest = [&]( const BOARD& aBoard ) + { + for( const FOOTPRINT_LOAD_TEST_CASE& fooprintTestCase : testCase.m_imageCases ) + { + BOOST_TEST_MESSAGE( "Checking for footprint with UUID: " + << fooprintTestCase.m_footprintUuid.AsString() ); + + const auto& image = static_cast( KI_TEST::RequireBoardItemWithTypeAndId( + aBoard, PCB_FOOTPRINT_T, fooprintTestCase.m_footprintUuid ) ); + + BOOST_CHECK_EQUAL( image.IsLocked(), fooprintTestCase.m_expectedLocked ); + BOOST_CHECK_EQUAL( image.GetPosition(), fooprintTestCase.m_expectedPos * 1000000 ); + } + }; + + KI_TEST::LoadAndTestBoardFile( testCase.m_boardFileRelativePath, true, doBoardTest ); + } +} \ No newline at end of file diff --git a/qa/tests/pcbnew/test_module.cpp b/qa/tests/pcbnew/test_module.cpp index e25e8c657a..ced0cd3663 100644 --- a/qa/tests/pcbnew/test_module.cpp +++ b/qa/tests/pcbnew/test_module.cpp @@ -27,6 +27,7 @@ #include #include +#include #include @@ -34,7 +35,16 @@ bool init_unit_test() { KIPLATFORM::APP::Init(); boost::unit_test::framework::master_test_suite().p_name.value = "Pcbnew module tests"; - return wxInitialize(); + + bool ok = wxInitialize(); + + if( ok ) + { + // need these for library image functions + wxInitAllImageHandlers(); + } + + return ok; } diff --git a/qa/tests/pcbnew/test_reference_image_load.cpp b/qa/tests/pcbnew/test_reference_image_load.cpp new file mode 100644 index 0000000000..3ebc20466d --- /dev/null +++ b/qa/tests/pcbnew/test_reference_image_load.cpp @@ -0,0 +1,126 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +struct REFERENCE_IMAGE_LOAD_TEST_FIXTURE +{ + REFERENCE_IMAGE_LOAD_TEST_FIXTURE() {} +}; + + +struct REFERENCE_IMAGE_LOAD_TEST_CASE +{ + // Which + KIID m_imageUuid; + bool m_expectedLocked; + VECTOR2I m_expectedPos; + double m_expectedScale; + // This should also check correct image decoding, as it won't work otherwise + VECTOR2I m_expectedPixelSize; +}; + + +struct REFERENCE_IMAGE_LOAD_BOARD_TEST_CASE +{ + // The board to load + wxString m_boardFileRelativePath; + // List of images to check + std::vector m_imageCases; +}; + +} // namespace + +BOOST_FIXTURE_TEST_CASE( ReferenceImageLoading, REFERENCE_IMAGE_LOAD_TEST_FIXTURE ) +{ + const std::vector testCases{ + { + "reference_images_load_save", + { + // From top to bottom in the board file + { + "7dde345e-020a-4fdd-af77-588b452be5e0", + false, + { 100, 46 }, + 1.0, + { 64, 64 }, + }, + { + "e4fd52dd-1d89-4c43-b621-aebfc9788d5c", + true, + { 100, 65 }, + 1.0, + { 64, 64 }, + }, + { + "d402397e-bce0-4cae-a398-b5aeef397e87", + false, + { 100, 90 }, + 2.0, + { 64, 64 }, // It's the same size, but scaled + }, + }, + }, + }; + + for( const REFERENCE_IMAGE_LOAD_BOARD_TEST_CASE& testCase : testCases ) + { + const auto doBoardTest = [&]( const BOARD& aBoard ) + { + for( const REFERENCE_IMAGE_LOAD_TEST_CASE& imageTestCase : testCase.m_imageCases ) + { + BOOST_TEST_MESSAGE( + "Checking for image with UUID: " << imageTestCase.m_imageUuid.AsString() ); + + const auto& image = + static_cast( KI_TEST::RequireBoardItemWithTypeAndId( + aBoard, PCB_REFERENCE_IMAGE_T, imageTestCase.m_imageUuid ) ); + + BOOST_CHECK_EQUAL( image.IsLocked(), imageTestCase.m_expectedLocked ); + BOOST_CHECK_EQUAL( image.GetPosition(), imageTestCase.m_expectedPos * 1000000 ); + BOOST_CHECK_CLOSE( image.GetImageScale(), imageTestCase.m_expectedScale, 1e-6 ); + + const BITMAP_BASE* bitmap = image.GetImage(); + + BOOST_REQUIRE( bitmap ); + + BOOST_TEST_MESSAGE( "Got underlying image" ); + + BOOST_CHECK_EQUAL( bitmap->GetSizePixels(), imageTestCase.m_expectedPixelSize ); + } + }; + + KI_TEST::LoadAndTestBoardFile( testCase.m_boardFileRelativePath, true, doBoardTest ); + } +} \ No newline at end of file