KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_lib_table_diff_merge.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25#include <qa_utils/file_utils.h>
27
32
33#include <board.h>
36
37#include <wx/file.h>
38#include <wx/filename.h>
39#include <wx/stdpaths.h>
40
41
42using namespace KICAD_DIFF;
43
44
45namespace
46{
47
48wxString writeProjectFile( BOARD& aBoard, const std::string& aFileName,
49 const wxString& aContent )
50{
51 wxFileName fn( aBoard.GetFileName() );
52 fn.SetFullName( wxString::FromUTF8( aFileName ) );
53
54 wxFile f;
55 BOOST_REQUIRE( f.Open( fn.GetFullPath(), wxFile::write ) );
56 BOOST_REQUIRE( f.Write( aContent ) );
57 f.Close();
58 return fn.GetFullPath();
59}
60
61
62const ITEM_CHANGE* findDocLevelChange( const DOCUMENT_DIFF& aDiff )
63{
64 for( const ITEM_CHANGE& c : aDiff.changes )
65 {
66 if( c.id.empty() )
67 return &c;
68 }
69
70 return nullptr;
71}
72
73
74const PROPERTY_DELTA* findProperty( const ITEM_CHANGE& aChange, const wxString& aName )
75{
76 for( const PROPERTY_DELTA& p : aChange.properties )
77 {
78 if( p.name == aName )
79 return &p;
80 }
81
82 return nullptr;
83}
84
85} // namespace
86
87
89{
91 m_ancDir( wxS( "kicad_libtbl_anc" ) ),
92 m_oursDir( wxS( "kicad_libtbl_ours" ) ),
93 m_theirsDir( wxS( "kicad_libtbl_theirs" ) )
94 {
95 KI_TEST::LoadBoard( m_settingsAnc, "complex_hierarchy", m_ancestor );
96 KI_TEST::LoadBoard( m_settingsOurs, "complex_hierarchy", m_ours );
97 KI_TEST::LoadBoard( m_settingsTheirs, "complex_hierarchy", m_theirs );
98
102
103 m_ancestor->SetFileName( m_ancDir.PathStr() + wxFILE_SEP_PATH + wxS( "board.kicad_pcb" ) );
104 m_ours->SetFileName( m_oursDir.PathStr() + wxFILE_SEP_PATH + wxS( "board.kicad_pcb" ) );
105 m_theirs->SetFileName( m_theirsDir.PathStr() + wxFILE_SEP_PATH + wxS( "board.kicad_pcb" ) );
106 }
107
109
113 std::unique_ptr<BOARD> m_ancestor;
114 std::unique_ptr<BOARD> m_ours;
115 std::unique_ptr<BOARD> m_theirs;
119};
120
121
122BOOST_FIXTURE_TEST_SUITE( LibTableDiffMerge, LIB_TABLE_DIFF_MERGE_FIXTURE )
123
124
125BOOST_AUTO_TEST_CASE( NoSiblingFilesEmitsNoDelta )
126{
127 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
128 DOCUMENT_DIFF result = differ.Diff();
129
130 if( const ITEM_CHANGE* docChange = findDocLevelChange( result ) )
131 {
132 BOOST_CHECK( findProperty( *docChange, DOC_PROP_FP_LIB_TABLE ) == nullptr );
133 BOOST_CHECK( findProperty( *docChange, DOC_PROP_SYM_LIB_TABLE ) == nullptr );
134 }
135}
136
137
138BOOST_AUTO_TEST_CASE( OursAddsFpLibTableEmitsDelta )
139{
140 writeProjectFile( *m_ours, FILEEXT::FootprintLibraryTableFileName,
141 wxS( "(fp_lib_table\n(version 7)\n)\n" ) );
142
143 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
144 DOCUMENT_DIFF result = differ.Diff();
145
146 const ITEM_CHANGE* docChange = findDocLevelChange( result );
147 BOOST_REQUIRE( docChange );
148
151 BOOST_CHECK_EQUAL( delta->before.ToDisplayString(), "(no fp-lib-table)" );
152 BOOST_CHECK( delta->after.ToDisplayString() != "(no fp-lib-table)" );
153}
154
155
156BOOST_AUTO_TEST_CASE( OursAddsSymLibTableEmitsDelta )
157{
158 writeProjectFile( *m_ours, FILEEXT::SymbolLibraryTableFileName,
159 wxS( "(sym_lib_table\n(version 7)\n)\n" ) );
160
161 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
162 DOCUMENT_DIFF result = differ.Diff();
163
164 const ITEM_CHANGE* docChange = findDocLevelChange( result );
165 BOOST_REQUIRE( docChange );
166
169 BOOST_CHECK_EQUAL( delta->before.ToDisplayString(), "(no sym-lib-table)" );
170 BOOST_CHECK( delta->after.ToDisplayString() != "(no sym-lib-table)" );
171}
172
173
174BOOST_AUTO_TEST_CASE( DivergentFpLibTableEmitsDelta )
175{
176 writeProjectFile( *m_ancestor, FILEEXT::FootprintLibraryTableFileName,
177 wxS( "(fp_lib_table\n(version 7)\n(lib (name old))\n)\n" ) );
178 writeProjectFile( *m_ours, FILEEXT::FootprintLibraryTableFileName,
179 wxS( "(fp_lib_table\n(version 7)\n(lib (name new))\n)\n" ) );
180
181 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
182 DOCUMENT_DIFF result = differ.Diff();
183
184 const ITEM_CHANGE* docChange = findDocLevelChange( result );
185 BOOST_REQUIRE( docChange );
186
189 BOOST_CHECK( delta->before.ToDisplayString() != delta->after.ToDisplayString() );
190}
191
192
193BOOST_AUTO_TEST_CASE( ApplierStagesOursFpLibTable )
194{
195 const wxString oursFp =
196 wxS( "(fp_lib_table\n(version 7)\n(lib (name FromOurs))\n)\n" );
197 writeProjectFile( *m_ours, FILEEXT::FootprintLibraryTableFileName, oursFp );
198
199 PCB_DIFFER diffAO( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
200 PCB_DIFFER diffAT( m_ancestor.get(), m_theirs.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
201 DOCUMENT_DIFF docAO = diffAO.Diff();
202 DOCUMENT_DIFF docAT = diffAT.Diff();
203
204 KICAD_MERGE_ENGINE engine;
205 MERGE_PLAN plan = engine.Plan( docAO, docAT );
206
207 PCB_MERGE_APPLIER applier( m_ancestor.get(), m_ours.get(), m_theirs.get(),
208 std::move( plan ) );
209 std::unique_ptr<BOARD> merged = applier.Apply();
210
211 BOOST_REQUIRE( merged );
212 BOOST_CHECK( applier.GetReport().projectFileTouched );
213 BOOST_CHECK( applier.GetReport().fpLibTableSet );
214 BOOST_CHECK_EQUAL( applier.GetReport().fpLibTable, oursFp );
215}
216
217
218BOOST_AUTO_TEST_CASE( ApplierStagesOursSymLibTable )
219{
220 const wxString oursSym =
221 wxS( "(sym_lib_table\n(version 7)\n(lib (name FromOurs))\n)\n" );
222 writeProjectFile( *m_ours, FILEEXT::SymbolLibraryTableFileName, oursSym );
223
224 PCB_DIFFER diffAO( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
225 PCB_DIFFER diffAT( m_ancestor.get(), m_theirs.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
226 DOCUMENT_DIFF docAO = diffAO.Diff();
227 DOCUMENT_DIFF docAT = diffAT.Diff();
228
229 KICAD_MERGE_ENGINE engine;
230 MERGE_PLAN plan = engine.Plan( docAO, docAT );
231
232 PCB_MERGE_APPLIER applier( m_ancestor.get(), m_ours.get(), m_theirs.get(),
233 std::move( plan ) );
234 std::unique_ptr<BOARD> merged = applier.Apply();
235
236 BOOST_REQUIRE( merged );
237 BOOST_CHECK( applier.GetReport().projectFileTouched );
238 BOOST_CHECK( applier.GetReport().symLibTableSet );
239 BOOST_CHECK_EQUAL( applier.GetReport().symLibTable, oursSym );
240}
241
242
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
const wxString & GetFileName() const
Definition board.h:454
Three-way merge plan generator.
MERGE_PLAN Plan(const DOCUMENT_DIFF &aAncestorOurs, const DOCUMENT_DIFF &aAncestorTheirs) const
Plan the merge given the canonical pair of diffs.
Diff two already-parsed BOARDs and produce a DOCUMENT_DIFF.
Definition pcb_differ.h:62
DOCUMENT_DIFF Diff() override
Produce a DOCUMENT_DIFF of the inputs the concrete differ was constructed with.
Materialize a MERGE_PLAN into a real merged BOARD.
std::unique_ptr< BOARD > Apply()
Produce the merged board.
const REPORT & GetReport() const
static const std::string SymbolLibraryTableFileName
static const std::string FootprintLibraryTableFileName
static std::vector< PENDING_PROPERTY > plan(const EDA_ITEM &aSource, const EDA_ITEM &aTarget, const std::set< wxString > &aEnabledKeys)
Target properties to write, paired with values read off the source.
const wxString DOC_PROP_SYM_LIB_TABLE
const wxString DOC_PROP_FP_LIB_TABLE
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
The full set of changes between two parsed documents of one type.
std::vector< ITEM_CHANGE > changes
One change record on a single item.
std::vector< PROPERTY_DELTA > properties
Result of planning a 3-way merge.
wxString fpLibTable
fp-lib-table content the applier resolved.
bool projectFileTouched
True iff the applier resolved state that lives in the .kicad_pro or a project sibling file.
wxString symLibTable
sym-lib-table content the applier resolved.
Single (name, before, after) triple for one mutated property on an item.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(NoSiblingFilesEmitsNoDelta)
static const ITEM_CHANGE * findDocLevelChange(const DOCUMENT_DIFF &aDiff)
Find the synthetic doc-level ITEM_CHANGE (empty KIID_PATH) in a diff result, returning nullptr if non...
static const PROPERTY_DELTA * findProperty(const ITEM_CHANGE &aChange, const wxString &aName)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
int delta
Definition of file extensions used in Kicad.