KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_sch_api_handler.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <memory>
21
22#include <boost/test/unit_test.hpp>
23
24#include <api/api_handler_sch.h>
25#include <api/api_utils.h>
26#include <api/common/commands/editor_commands.pb.h>
27#include <api/common/envelope.pb.h>
29#include <api/schematic/schematic_types.pb.h>
32
33#include <schematic.h>
34
35
36namespace
37{
38
39struct API_HANDLER_SCH_FIXTURE
40{
41 SETTINGS_MANAGER m_settingsManager;
42 std::unique_ptr<SCHEMATIC> m_schematic;
43 SCHEMATIC* m_schematicSlot = nullptr;
44 std::shared_ptr<HEADLESS_SCH_CONTEXT> m_context;
45
46 SCHEMATIC* loadSchematic( const wxString& aRelPath )
47 {
48 KI_TEST::LoadSchematic( m_settingsManager, aRelPath, m_schematic );
49 m_schematicSlot = m_schematic.get();
50 m_context = std::make_shared<HEADLESS_SCH_CONTEXT>( &m_schematicSlot,
51 &m_settingsManager.Prj() );
52 return m_schematic.get();
53 }
54};
55
56
57kiapi::common::types::DocumentSpecifier makeDocument( const SCHEMATIC& aSchematic )
58{
59 kiapi::common::types::DocumentSpecifier document;
60 document.set_type( kiapi::common::types::DocumentType::DOCTYPE_SCHEMATIC );
61 kiapi::common::PackProject( *document.mutable_project(), aSchematic.Project() );
62
63 return document;
64}
65
66
67kiapi::common::ApiRequest makeBeginCommitRequest( const SCHEMATIC& aSchematic )
68{
69 kiapi::common::commands::BeginCommit command;
70 *command.mutable_header()->mutable_document() = makeDocument( aSchematic );
71
72 kiapi::common::ApiRequest request;
73 request.mutable_header()->set_client_name( "kicad.qa" );
74 BOOST_REQUIRE( request.mutable_message()->PackFrom( command ) );
75
76 return request;
77}
78
79
80kiapi::common::ApiRequest makeRevertRequest( const SCHEMATIC& aSchematic )
81{
82 kiapi::common::commands::RevertDocument command;
83 *command.mutable_document() = makeDocument( aSchematic );
84
85 kiapi::common::ApiRequest request;
86 request.mutable_header()->set_client_name( "kicad.qa" );
87 BOOST_REQUIRE( request.mutable_message()->PackFrom( command ) );
88
89 return request;
90}
91
92
93}
94
95
96BOOST_FIXTURE_TEST_SUITE( ApiHandlerSch, API_HANDLER_SCH_FIXTURE )
97
98
99BOOST_AUTO_TEST_CASE( RevertDocumentRejectedWithOpenCommit )
100{
101 SCHEMATIC* schematic = loadSchematic( wxS( "api_kitchen_sink" ) );
102
103 API_HANDLER_SCH handler( m_context );
104
105 kiapi::common::ApiRequest beginRequest = makeBeginCommitRequest( *schematic );
106 BOOST_REQUIRE( handler.Handle( beginRequest ).has_value() );
107
108 kiapi::common::ApiRequest request = makeRevertRequest( *schematic );
109 API_RESULT result = handler.Handle( request );
110
111 BOOST_REQUIRE( !result.has_value() );
112 BOOST_CHECK_EQUAL( result.error().status(), kiapi::common::ApiStatusCode::AS_BUSY );
113 BOOST_CHECK( result.error().error_message().find( "commit" ) != std::string::npos );
114}
115
116
117
118BOOST_AUTO_TEST_CASE( CustomPropertyCannotDuplicateSystemProperty )
119{
120 SCHEMATIC* schematic = loadSchematic( wxS( "api_kitchen_sink" ) );
121
122 API_HANDLER_SCH handler( m_context );
123 ApiRequest beginRequest = makeBeginCommitRequest( *schematic );
124 BOOST_REQUIRE( handler.Handle( beginRequest ).has_value() );
125
126 commands::CreateItems command;
127 command.mutable_header()->mutable_document()->CopyFrom( makeDocument( *schematic ) );
128
129 schematic::types::SchematicLine line;
130 line.mutable_id()->set_value( "83618809-06d6-4cbe-ba0e-ec60fe58921c" );
131 line.set_type( schematic::types::SchematicLineType::SLT_WIRE );
132 line.add_custom_properties()->set_key( "linE Width" );
133 line.add_custom_properties()->set_key( "start X" );
134
135 command.add_items()->PackFrom( line );
136
137 ApiRequest request;
138 request.mutable_header()->set_client_name( "kicad.qa" );
139 BOOST_REQUIRE( request.mutable_message()->PackFrom( command ) );
140
141 API_RESULT result = handler.Handle( request );
142 BOOST_REQUIRE( result.has_value() );
143
144 commands::CreateItemsResponse response;
145 BOOST_REQUIRE( result->message().UnpackTo( &response ) );
146 BOOST_REQUIRE_EQUAL( response.created_items_size(), 1 );
147
148 const commands::ItemStatus& status = response.created_items( 0 ).status();
149
150 // Should be rejected; duplicates built in property
151 BOOST_CHECK_EQUAL( status.code(), kiapi::common::commands::ItemStatusCode::ISC_INVALID_DATA );
152 BOOST_CHECK_NE( status.error_message().find( "Invalid custom properties" ), std::string::npos );
153}
154
155
156BOOST_AUTO_TEST_CASE( SymbolFieldTakesPrecedenceOverCustomProperty )
157{
158 SCHEMATIC* schematic = loadSchematic( wxS( "api_kitchen_sink" ) );
159
160 API_HANDLER_SCH handler( m_context );
161 ApiRequest beginRequest = makeBeginCommitRequest( *schematic );
162 BOOST_REQUIRE( handler.Handle( beginRequest ).has_value() );
163
164 commands::CreateItems command;
165 command.mutable_header()->mutable_document()->CopyFrom( makeDocument( *schematic ) );
166
167 schematic::types::SchematicSymbolInstance symbol;
168 symbol.mutable_id()->set_value( "f8688bac-2fcb-4184-ab0e-0cf46a139c43" );
169 symbol.mutable_transform()->set_orientation( schematic::types::SchematicSymbolOrientation::SSO_0 );
170
171 schematic::types::SchematicField* field = symbol.add_user_fields();
172 field->set_name( "MPN" );
173 field->mutable_text()->set_text( "123" );
174
175 types::CustomProperty* prop = symbol.add_custom_properties();
176 prop->set_key( "MPN" );
177 prop->set_value( "456" );
178
179 command.add_items()->PackFrom( symbol );
180
181 ApiRequest request;
182 request.mutable_header()->set_client_name( "kicad.qa" );
183 BOOST_REQUIRE( request.mutable_message()->PackFrom( command ) );
184
185 API_RESULT result = handler.Handle( request );
186 BOOST_REQUIRE( result.has_value() );
187
188 commands::CreateItemsResponse response;
189 BOOST_REQUIRE( result->message().UnpackTo( &response ) );
190 BOOST_REQUIRE_EQUAL( response.created_items_size(), 1 );
191
192 const commands::ItemStatus& status = response.created_items( 0 ).status();
193
194 // The field takes precedence: a custom property duplicating a field name is rejected.
195 BOOST_CHECK_EQUAL( status.code(), kiapi::common::commands::ItemStatusCode::ISC_INVALID_DATA );
196 BOOST_CHECK_NE( status.error_message().find( "MPN" ), std::string::npos );
197}
198
tl::expected< ApiResponse, ApiResponseStatus > API_RESULT
Definition api_handler.h:42
API_RESULT Handle(ApiRequest &aMsg)
Attempt to handle the given API request, if a handler exists in this class for the message.
Holds all the data relating to one schematic.
Definition schematic.h:148
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:170
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
KICOMMON_API void PackProject(types::ProjectSpecifier &aOutput, const PROJECT &aInput)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(RevertDocumentRejectedWithOpenCommit)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")