KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_classes_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
26
31
32#include <board.h>
35#include <netclass.h>
37
38
39using namespace KICAD_DIFF;
40
41
50{
52 {
53 KI_TEST::LoadBoard( m_settingsAnc, "complex_hierarchy", m_ancestor );
54 KI_TEST::LoadBoard( m_settingsOurs, "complex_hierarchy", m_ours );
55 KI_TEST::LoadBoard( m_settingsTheirs, "complex_hierarchy", m_theirs );
56
60 BOOST_REQUIRE( m_ancestor->GetDesignSettings().m_NetSettings );
61 BOOST_REQUIRE( m_ours->GetDesignSettings().m_NetSettings );
62 BOOST_REQUIRE( m_theirs->GetDesignSettings().m_NetSettings );
63 }
64
68 std::unique_ptr<BOARD> m_ancestor;
69 std::unique_ptr<BOARD> m_ours;
70 std::unique_ptr<BOARD> m_theirs;
71};
72
73
76static const ITEM_CHANGE* findDocLevelChange( const DOCUMENT_DIFF& aDiff )
77{
78 for( const ITEM_CHANGE& c : aDiff.changes )
79 {
80 if( c.id.empty() )
81 return &c;
82 }
83
84 return nullptr;
85}
86
87
88static const PROPERTY_DELTA* findProperty( const ITEM_CHANGE& aChange, const wxString& aName )
89{
90 for( const PROPERTY_DELTA& p : aChange.properties )
91 {
92 if( p.name == aName )
93 return &p;
94 }
95
96 return nullptr;
97}
98
99
100BOOST_FIXTURE_TEST_SUITE( NetClassesDiffMerge, NET_CLASSES_DIFF_MERGE_FIXTURE )
101
102
103// Two fresh loads should produce no net-classes delta, because the persisted
104// NET_SETTINGS content is identical.
105BOOST_AUTO_TEST_CASE( NoChangeEmitsNoNetClassesDelta )
106{
107 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
108 DOCUMENT_DIFF result = differ.Diff();
109
110 if( const ITEM_CHANGE* docChange = findDocLevelChange( result ) )
111 {
112 BOOST_CHECK( findProperty( *docChange, DOC_PROP_NET_CLASSES ) == nullptr );
113 }
114}
115
116
117// An edit to the default netclass's clearance must surface as a
118// DOC_PROP_NET_CLASSES delta with different before / after summary strings.
119BOOST_AUTO_TEST_CASE( DefaultClearanceEditEmitsDelta )
120{
121 m_ours->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 350000 );
122
123 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
124 DOCUMENT_DIFF result = differ.Diff();
125
126 const ITEM_CHANGE* docChange = findDocLevelChange( result );
127 BOOST_REQUIRE( docChange );
128
131
132 BOOST_CHECK( delta->before.ToDisplayString() != delta->after.ToDisplayString() );
133}
134
135
136// Adding a new named netclass on one side must surface as a delta.
137BOOST_AUTO_TEST_CASE( NewNamedNetclassEmitsDelta )
138{
139 std::shared_ptr<NETCLASS> hs = std::make_shared<NETCLASS>( wxS( "HighSpeed" ), false );
140 hs->SetClearance( 150000 );
141 hs->SetTrackWidth( 127000 );
142
143 std::map<wxString, std::shared_ptr<NETCLASS>> classes =
144 m_ours->GetDesignSettings().m_NetSettings->GetNetclasses();
145 classes[wxS( "HighSpeed" )] = hs;
146 m_ours->GetDesignSettings().m_NetSettings->SetNetclasses( classes );
147
148 PCB_DIFFER differ( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
149 DOCUMENT_DIFF result = differ.Diff();
150
151 const ITEM_CHANGE* docChange = findDocLevelChange( result );
152 BOOST_REQUIRE( docChange );
153
156
157 BOOST_CHECK( delta->before.ToDisplayString() != delta->after.ToDisplayString() );
158}
159
160
161// Applier path: a TAKE_OURS resolution of DOC_PROP_NET_CLASSES via MERGE_PROPS
162// copies ours' net settings into result without aliasing ours' shared_ptr.
163// Editing ours after Apply must NOT bleed through into the merged board.
164BOOST_AUTO_TEST_CASE( ApplierTakeOursCopiesWithoutAliasing )
165{
166 m_ours->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 350000 );
167
168 PCB_DIFFER diffAO( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
169 PCB_DIFFER diffAT( m_ancestor.get(), m_theirs.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
170 DOCUMENT_DIFF docAO = diffAO.Diff();
171 DOCUMENT_DIFF docAT = diffAT.Diff();
172
173 KICAD_MERGE_ENGINE engine;
174 MERGE_PLAN plan = engine.Plan( docAO, docAT );
175
176 PCB_MERGE_APPLIER applier( m_ancestor.get(), m_ours.get(), m_theirs.get(),
177 std::move( plan ) );
178 std::unique_ptr<BOARD> merged = applier.Apply();
179
180 BOOST_REQUIRE( merged );
181 BOOST_REQUIRE( merged->GetDesignSettings().m_NetSettings );
182 BOOST_CHECK( applier.GetReport().projectFileTouched );
183
185 merged->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->GetClearance(),
186 350000 );
187
188 // Pointer-distinct from ours: detach + CopyFrom path must produce a
189 // standalone NET_SETTINGS instance.
190 BOOST_CHECK( merged->GetDesignSettings().m_NetSettings.get()
191 != m_ours->GetDesignSettings().m_NetSettings.get() );
192
193 // Mutating ours after Apply must not affect merged.
194 m_ours->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 999999 );
195
197 merged->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->GetClearance(),
198 350000 );
199}
200
201
202// Applier path: a TAKE_THEIRS-equivalent resolution copies theirs' settings.
203// The engine routes one-sided edits to the side that made them, so editing
204// only theirs and planning gives a theirs-side resolution.
205BOOST_AUTO_TEST_CASE( ApplierTakeTheirsCopiesTheirsSettings )
206{
207 m_theirs->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetTrackWidth( 300000 );
208
209 PCB_DIFFER diffAO( m_ancestor.get(), m_ours.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
210 PCB_DIFFER diffAT( m_ancestor.get(), m_theirs.get(), wxS( "complex_hierarchy.kicad_pcb" ) );
211 DOCUMENT_DIFF docAO = diffAO.Diff();
212 DOCUMENT_DIFF docAT = diffAT.Diff();
213
214 KICAD_MERGE_ENGINE engine;
215 MERGE_PLAN plan = engine.Plan( docAO, docAT );
216
217 PCB_MERGE_APPLIER applier( m_ancestor.get(), m_ours.get(), m_theirs.get(),
218 std::move( plan ) );
219 std::unique_ptr<BOARD> merged = applier.Apply();
220
221 BOOST_REQUIRE( merged );
222 BOOST_CHECK( applier.GetReport().projectFileTouched );
224 merged->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->GetTrackWidth(),
225 300000 );
226}
227
228
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:52
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
const wxString DOC_PROP_NET_CLASSES
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.
bool projectFileTouched
True iff the applier resolved state that lives in the .kicad_pro or a project sibling file.
Single (name, before, after) triple for one mutated property on an item.
Fixture: three independent loads of the same canonical board, used to play the role of ancestor / our...
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
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...
BOOST_AUTO_TEST_CASE(NoChangeEmitsNoNetClassesDelta)
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