Add CADSTAR Parts Library (.lib) parser and qa tests
This commit is contained in:
parent
e51594cdf5
commit
379e3b2fbb
|
@ -262,6 +262,7 @@ set( PLUGINS_ALTIUM_SRCS
|
|||
|
||||
set( PLUGINS_CADSTAR_SRCS
|
||||
plugins/cadstar/cadstar_archive_parser.cpp
|
||||
plugins/cadstar/cadstar_parts_lib_parser.cpp
|
||||
)
|
||||
|
||||
set( PLUGINS_EAGLE_SRCS
|
||||
|
|
|
@ -0,0 +1,521 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2022 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pegtl.hpp>
|
||||
|
||||
namespace CADSTAR_PARTS_LIB
|
||||
{
|
||||
using namespace tao::pegtl;
|
||||
|
||||
//-------------------- Grammar definition ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Needed, because PEGTL "space" includes newline characters
|
||||
*/
|
||||
struct WHITESPACE : one<' ', '\t'>{};
|
||||
|
||||
/**
|
||||
* Empty line with whitespaces
|
||||
*/
|
||||
struct EMPTY_LINE : seq< bol, star<WHITESPACE>, eol>{};
|
||||
|
||||
/**
|
||||
* Any text in the format can span multiple lines using '&'
|
||||
*/
|
||||
struct LINE_CONTINUATION : seq<one<'&'>, eol>{};
|
||||
|
||||
|
||||
struct WHITESPACE_OR_CONTINUATION : sor<WHITESPACE, LINE_CONTINUATION> {};
|
||||
|
||||
/**
|
||||
* String segment( no line continuation ), with exclusion rules
|
||||
*/
|
||||
template <typename... EXCLUSION_RULES>
|
||||
struct STR_SEGMENT_EXCLUDING : plus<not_at<sor<eolf, LINE_CONTINUATION, EXCLUSION_RULES...>>, any>{};
|
||||
|
||||
/**
|
||||
* String with optional line continuation and exclusion rules
|
||||
*/
|
||||
template <typename... EXCLUSION_RULES>
|
||||
struct STRING_EXCLUDING : plus<STR_SEGMENT_EXCLUDING<EXCLUSION_RULES...>, opt<LINE_CONTINUATION>> {};
|
||||
|
||||
struct QUOTED_STRING : seq<one<'"'>, STRING_EXCLUDING<one<'"'>>, one<'"'>> {};
|
||||
|
||||
/**
|
||||
* Control character with or without preceding whitespace
|
||||
*/
|
||||
template <char... CHAR_TO_FIND>
|
||||
struct spaced_ch : seq<star<WHITESPACE>, one<CHAR_TO_FIND...>>{};
|
||||
|
||||
|
||||
// **************
|
||||
// * FORMAT *
|
||||
// **************
|
||||
|
||||
// Definition of "Format"
|
||||
// # FORMAT <current format number>
|
||||
struct CURRENT_FORMAT_NUMBER : plus<digit> {};
|
||||
struct FORMAT : seq
|
||||
<
|
||||
bol,
|
||||
one<'#'>,
|
||||
star<WHITESPACE>,
|
||||
TAO_PEGTL_ISTRING( "FORMAT" ),
|
||||
star<WHITESPACE>,
|
||||
CURRENT_FORMAT_NUMBER,
|
||||
opt<eol>
|
||||
> {};
|
||||
|
||||
|
||||
// **************
|
||||
// * PART ENTRY *
|
||||
// **************
|
||||
|
||||
// Part Header
|
||||
// -----------
|
||||
//.<Part name>_[(<Part number>)][:<Part version>][;<Description>]
|
||||
|
||||
// string filters:
|
||||
struct PART_HEADER_START : one <'.'>{};
|
||||
struct PART_NAME_FILTER : sor<spaced_ch<'('>, spaced_ch<':'>, spaced_ch<';'>>{};
|
||||
struct PART_NUMBER_FILTER : one<')'>{};
|
||||
struct PART_VERSION_FILTER : spaced_ch<';'>{};
|
||||
|
||||
// part header elements:
|
||||
struct PART_NAME : STRING_EXCLUDING<PART_NAME_FILTER> {};
|
||||
struct PART_NUMBER : STRING_EXCLUDING<PART_NUMBER_FILTER> {};
|
||||
struct PART_VERSION : STRING_EXCLUDING<PART_VERSION_FILTER> {};
|
||||
struct PART_DESCRIPTION : STRING_EXCLUDING<> {};
|
||||
|
||||
struct PART_HEADER :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
one<'.'>,
|
||||
must<PART_NAME>,
|
||||
opt<seq<spaced_ch<'('>, PART_NUMBER, one<')'>>>,
|
||||
opt<seq<spaced_ch<':'>, PART_VERSION>>,
|
||||
opt<seq<spaced_ch<';'>, PART_DESCRIPTION>>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// Part - PCB Component
|
||||
// --------------------
|
||||
//<PCB Component Refname>[_(<PCB Alternate Refname>)]
|
||||
|
||||
// string filters:
|
||||
struct PCB_COMPONENT_FILTER : spaced_ch<'('>{};
|
||||
struct PCB_ALTERNATE_FILTER : one<')'>{};
|
||||
|
||||
// pcb component elements
|
||||
struct PCB_COMPONENT : STRING_EXCLUDING<PCB_COMPONENT_FILTER> {};
|
||||
struct PCB_ALTERNATE : STRING_EXCLUDING<PCB_ALTERNATE_FILTER> {};
|
||||
|
||||
struct PART_PCB_COMPONENT :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
PCB_COMPONENT,
|
||||
opt<seq<spaced_ch<'('>, PCB_ALTERNATE, one<')'>>>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// Part Value
|
||||
// -----------
|
||||
//[*VALUE_<Value>]
|
||||
struct VALUE : STRING_EXCLUDING<> {};
|
||||
struct PART_VALUE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*VALUE"),
|
||||
plus<WHITESPACE>,
|
||||
VALUE,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
struct PINNUM : plus<digit> {};
|
||||
|
||||
// Pin Names
|
||||
//[*PNM_<Pinnum>=<Pinname>[_<Pinnum>=<Pinname>]_etc]
|
||||
// Maximum 10 characters allowed for Pinname according to documentation
|
||||
struct PINNAME : rep_min_max<1,10,alnum> {};
|
||||
struct PINNAME_ENTRY :
|
||||
seq
|
||||
<
|
||||
plus<WHITESPACE_OR_CONTINUATION>,
|
||||
PINNUM,
|
||||
one<'='>,
|
||||
PINNAME
|
||||
>
|
||||
{};
|
||||
|
||||
struct PIN_NAMES_LIST :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*PNM"),
|
||||
plus<PINNAME_ENTRY>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// Pin Labels
|
||||
//[*PLB_<Pinnum>=<Pinlabel>[_<Pinnum>=<Pinlabel>]_etc]
|
||||
struct PINLABEL : sor<QUOTED_STRING, STRING_EXCLUDING<WHITESPACE>> {};
|
||||
struct PINLABEL_ENTRY :
|
||||
seq
|
||||
<
|
||||
plus<WHITESPACE_OR_CONTINUATION>,
|
||||
PINNUM,
|
||||
one<'='>,
|
||||
PINLABEL
|
||||
>
|
||||
{};
|
||||
|
||||
struct PIN_LABELS_LIST :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*PLB"),
|
||||
plus<PINLABEL_ENTRY>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// Pin Equivalences
|
||||
//[*EQU_<PinIdentifier>=<PinIdentifier>[=<PinIdentifier>=<PinIdentifier>_etc ...]]
|
||||
struct EQUIVALENT_PIN : PINNUM {}; // same grammar but different action to be applied
|
||||
struct EQUIVALENT_PINS_GROUP :
|
||||
seq
|
||||
<
|
||||
plus<WHITESPACE_OR_CONTINUATION>,
|
||||
EQUIVALENT_PIN,
|
||||
plus<one<'='>, EQUIVALENT_PIN>
|
||||
>
|
||||
{};
|
||||
|
||||
struct PIN_EQUIVALENCES :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*EQU"),
|
||||
EQUIVALENT_PINS_GROUP,
|
||||
star<one<','>, EQUIVALENT_PINS_GROUP>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
// INTERNAL AND EXTERNAL PIN SWAPPING
|
||||
// *SYM_[<Element name>]
|
||||
struct SYM_ELEMENT_NAME : STRING_EXCLUDING<> {};
|
||||
struct SYM_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*SYM"),
|
||||
star<WHITESPACE>,
|
||||
opt<SYM_ELEMENT_NAME>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
struct GATE_PINS_LIST :
|
||||
seq
|
||||
<
|
||||
plus<WHITESPACE>,
|
||||
EQUIVALENT_PIN,
|
||||
star
|
||||
<
|
||||
plus<WHITESPACE_OR_CONTINUATION>,
|
||||
EQUIVALENT_PIN
|
||||
>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*INT_<Pinnum>_[<Pinnum>_ etc ...]]
|
||||
struct INTERNAL_SWAP_GATE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*INT"),
|
||||
GATE_PINS_LIST,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*EXT_<Pinnum>_[<Pinnum>_ etc ...]]
|
||||
struct EXTERNAL_SWAP_GATE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*EXT"),
|
||||
GATE_PINS_LIST,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// Internal swapping group E.g.:
|
||||
//*SYM SYM1
|
||||
//*INT 2 3
|
||||
//*INT 4 5
|
||||
struct INTERNAL_SWAP_GROUP :
|
||||
seq
|
||||
<
|
||||
SYM_LINE,
|
||||
plus<INTERNAL_SWAP_GATE>
|
||||
>
|
||||
{};
|
||||
|
||||
// External swapping group E.g.:
|
||||
//*SYM SYM1
|
||||
//*EXT 2 3
|
||||
//*EXT 4 5
|
||||
struct EXTERNAL_SWAP_GROUP :
|
||||
seq
|
||||
<
|
||||
SYM_LINE,
|
||||
plus<EXTERNAL_SWAP_GATE>
|
||||
>
|
||||
{};
|
||||
|
||||
// Part Definition
|
||||
// -----------
|
||||
//[*DFN_<Definition name>]
|
||||
struct DEFINITION_NAME : STRING_EXCLUDING<> {};
|
||||
struct DFN_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*DFN"),
|
||||
plus<WHITESPACE>,
|
||||
DEFINITION_NAME,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*NGS]
|
||||
struct NGS_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*NGS"),
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*NPV]
|
||||
struct NPV_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*NPV"),
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*STM_<Component name stem>]
|
||||
struct STEM : STRING_EXCLUDING<> {};
|
||||
struct STM_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*STM"),
|
||||
plus<WHITESPACE>,
|
||||
STEM,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*MXP <Maximum number of connector pins>]
|
||||
struct MAX_PIN_COUNT : plus<digit> {};
|
||||
struct MXP_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*MXP"),
|
||||
plus<WHITESPACE>,
|
||||
MAX_PIN_COUNT,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[*SPI_[(<Part name>)]_[<Model>]_<Component Value>]
|
||||
struct SPICE_PART_NAME : STRING_EXCLUDING< one<')'> > {};
|
||||
struct SPICE_FIRST : sor<QUOTED_STRING, STRING_EXCLUDING<WHITESPACE>> {};
|
||||
struct SPICE_SECOND : sor<QUOTED_STRING, STRING_EXCLUDING<WHITESPACE>> {};
|
||||
struct SPI_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*SPI"),
|
||||
plus<WHITESPACE>,
|
||||
opt<seq<spaced_ch<'('>, SPICE_PART_NAME, one<')'>>>,
|
||||
plus<WHITESPACE>,
|
||||
SPICE_FIRST, // Spice Value or Model
|
||||
opt<plus<WHITESPACE>, SPICE_SECOND>, // Spice Value
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
//[*PAC_(<Part name>)_<Acceptance Text>]
|
||||
struct ACCEPTANCE_PART_NAME : STRING_EXCLUDING< one<')'> > {};
|
||||
struct ACCEPTANCE_TEXT : STRING_EXCLUDING<> {};
|
||||
struct PAC_LINE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
TAO_PEGTL_ISTRING( "*PAC"),
|
||||
plus<WHITESPACE>,
|
||||
opt<seq<spaced_ch<'('>, ACCEPTANCE_PART_NAME, one<')'>>>,
|
||||
plus<WHITESPACE>,
|
||||
ACCEPTANCE_TEXT,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
// User defined part attributes
|
||||
// -----------
|
||||
//[*<User-defined name>_<Value>]
|
||||
struct USER_PART_ATTRIBUTE_NAME : sor<QUOTED_STRING, STRING_EXCLUDING<WHITESPACE>> {};
|
||||
struct USER_PART_ATTRIBUTE_VALUE : STRING_EXCLUDING<> {};
|
||||
struct USER_PART_ATTRIBUTE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
one<'*'>,
|
||||
USER_PART_ATTRIBUTE_NAME,
|
||||
plus<WHITESPACE>,
|
||||
USER_PART_ATTRIBUTE_VALUE,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//----------------------------------------------------
|
||||
// In-built attributes: schematic, PCB, both (sch+pcb) and parts
|
||||
//----------------------------------------------------
|
||||
struct READONLY : one <'!'>{};
|
||||
struct ATTRIBUTE_NAME : sor<QUOTED_STRING, STRING_EXCLUDING< spaced_ch<'('>>> {};
|
||||
struct ATTRIBUTE_VALUE : sor<QUOTED_STRING, STRING_EXCLUDING< one<')'>>> {};
|
||||
|
||||
template<char START_TOKEN>
|
||||
struct GENERIC_ATTRIBUTE :
|
||||
seq
|
||||
<
|
||||
bol,
|
||||
one<START_TOKEN>,
|
||||
opt<READONLY>,
|
||||
ATTRIBUTE_NAME,
|
||||
spaced_ch<'('>,
|
||||
ATTRIBUTE_VALUE,
|
||||
one<')'>,
|
||||
opt<eol>
|
||||
>
|
||||
{};
|
||||
|
||||
//[$[!]<SCM Attribute name>(<Attribute value>)]
|
||||
struct SCM_ATTRIBUTE : GENERIC_ATTRIBUTE<'$'>{};
|
||||
|
||||
|
||||
//[%[!]<PCB Attribute name>(<Attribute value>)]
|
||||
struct PCB_ATTRIBUTE : GENERIC_ATTRIBUTE<'%'>{};
|
||||
|
||||
|
||||
//[~[!]<Parts Library Attribute Name>(<Attribute Value>)]
|
||||
struct PART_ATTRIBUTE : GENERIC_ATTRIBUTE<'~'>{};
|
||||
|
||||
|
||||
//[@[!]<SCM/PCB Attribute name>(<Attribute value>)]
|
||||
struct SCH_PCB_ATTRIBUTE : GENERIC_ATTRIBUTE<'@'>{};
|
||||
|
||||
|
||||
//******************
|
||||
// Join all together
|
||||
|
||||
struct PART_ENTRY :
|
||||
seq
|
||||
<
|
||||
PART_HEADER, //.<Part name>[ (1234): 1 ;<Description>]
|
||||
PART_PCB_COMPONENT, //<PCB Component Refname> [(Alternate)]
|
||||
|
||||
// In any order:
|
||||
star<sor<
|
||||
PART_VALUE, //[*VALUE <Value>]
|
||||
PIN_NAMES_LIST, //[*PNM <ID><Name>[ <ID><Name>] ...]
|
||||
PIN_LABELS_LIST, //[*PLB <ID><Label>[ <ID><Label>] ...]
|
||||
PIN_EQUIVALENCES, //[*EQU_<ID>=<ID>[=<ID>=<ID>_etc ...]]
|
||||
INTERNAL_SWAP_GROUP, //[*SYM SYM1 |*INT 2 3 |*INT 4 5]
|
||||
EXTERNAL_SWAP_GROUP, //[*SYM SYM1 |*EXT 2 3 |*EXT 4 5]
|
||||
DFN_LINE, //[*DFN_<Definition name>]
|
||||
NGS_LINE, //[*NGS]
|
||||
NPV_LINE, //[*NPV]
|
||||
STM_LINE, //[*STM_<Component name stem>]
|
||||
MXP_LINE, //[*MXP <Maximum number of connector pins>]
|
||||
SPI_LINE, //[*SPI_[(<Part name>)]_[<Model>]_<Component Value>]
|
||||
PAC_LINE, //[*PAC_(<Part name>)_<Acceptance Text>]
|
||||
USER_PART_ATTRIBUTE, //[*<User-defined name>_<Value>]
|
||||
SCM_ATTRIBUTE, //[$[!]<SCM Attribute name>(<Attribute value>)]
|
||||
PCB_ATTRIBUTE, //[%[!]<PCB Attribute name>(<Attribute value>)]
|
||||
PART_ATTRIBUTE, //[~[!]<Parts Library Attribute Name>(<Attribute Value>)]
|
||||
SCH_PCB_ATTRIBUTE //[@[!]<SCM/PCB Attribute name>(<Attribute value>)]
|
||||
>>
|
||||
>
|
||||
{};
|
||||
|
||||
struct UNMATCHED_CONTENT : STRING_EXCLUDING<FORMAT, PART_ENTRY> {}; //@todo remove once parser is complete
|
||||
|
||||
/**
|
||||
* Grammar for CADSTAR Parts Library file format (*.lib)
|
||||
*/
|
||||
struct GRAMMAR :
|
||||
must<seq<
|
||||
opt<FORMAT>,
|
||||
plus
|
||||
<
|
||||
sor
|
||||
<
|
||||
PART_ENTRY,
|
||||
UNMATCHED_CONTENT, //@todo remove once parser is complete
|
||||
EMPTY_LINE // optional empty line
|
||||
>,
|
||||
opt<eol>
|
||||
>,
|
||||
opt<TAO_PEGTL_ISTRING( ".END"), opt<eol>>,
|
||||
star<EMPTY_LINE>,
|
||||
must<eolf>
|
||||
>>
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
* Grammar to parse the file header only.
|
||||
* In general a valid file should have `#FORMAT 32` in the first line but there appear to be some
|
||||
* files that ommit the format specifier and start straight away with the part definitions. Just
|
||||
* in case, we will also allow the first part to be up to 5 lines into the file (arbitrary number
|
||||
* just to limit the time spent in reading a file header to determine whether it is valid).
|
||||
*/
|
||||
struct VALID_HEADER : sor<FORMAT, seq< rep_max<5,EMPTY_LINE>, PART_HEADER>>{};
|
||||
|
||||
} // namespace CADSTAR_PART_LIB
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CADSTAR_PARTS_LIB_MODEL_H
|
||||
#define CADSTAR_PARTS_LIB_MODEL_H
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct CADSTAR_PART_ENTRY;
|
||||
struct CADSTAR_SWAP_GROUP;
|
||||
struct CADSTAR_ATTRIBUTE_VALUE;
|
||||
|
||||
/**
|
||||
* CADSTAR Parts Library (*.lib) model - a data structure describing the contents of the
|
||||
* file format
|
||||
*/
|
||||
struct CADSTAR_PARTS_LIB_MODEL
|
||||
{
|
||||
std::optional<long> m_FormatNumber;
|
||||
std::vector<CADSTAR_PART_ENTRY> m_PartEntries;
|
||||
};
|
||||
|
||||
|
||||
struct CADSTAR_PART_ENTRY
|
||||
{
|
||||
std::string m_Name;
|
||||
std::optional<std::string> m_Number;
|
||||
std::optional<std::string> m_Version;
|
||||
std::optional<std::string> m_Description;
|
||||
std::string m_Pcb_component;
|
||||
std::optional<std::string> m_Pcb_alternate;
|
||||
std::optional<std::string> m_Value; // *VALUE Note: ? character = the start of a new line
|
||||
std::optional<std::string> m_PartDefinitionName; // *DFN
|
||||
std::string m_ComponentStem = "";
|
||||
std::optional<long> m_MaxPinCount;
|
||||
|
||||
std::optional<std::string> m_SpicePartName;
|
||||
std::optional<std::string> m_SpiceModel;
|
||||
std::optional<std::string> m_SpiceValue;
|
||||
|
||||
std::optional<std::string> m_AcceptancePartName;
|
||||
std::optional<std::string> m_AcceptanceText;
|
||||
|
||||
bool m_GateSwappingAllowed = true;
|
||||
bool m_PinsVisible = true;
|
||||
|
||||
/**
|
||||
* Map of pin numbers to alphanumeric pin names
|
||||
* Pin names can be a maximum of 10 characters
|
||||
* (Typically used for naming of BGA pads)
|
||||
*
|
||||
* E.g: *PNM 1=A1 2=A2 3=A3 4=B1 5=B2 6=B3
|
||||
*/
|
||||
std::map<long, std::string> m_PinNamesMap;
|
||||
|
||||
/**
|
||||
* Map of pin numbers to alphanumeric pin labels
|
||||
*
|
||||
* E.g: *PLB 1=STROBE 2=OFFSET 3=OFFSET 5=+ 6=+v
|
||||
*/
|
||||
std::map<long, std::string> m_PinLabelsMap;
|
||||
|
||||
/**
|
||||
* Groups of pins that are interchangeable with each other
|
||||
*
|
||||
* E.g: *EQU 2=1, 6=5, 8=9=10, 12=13
|
||||
*/
|
||||
std::vector<std::vector<long>> m_PinEquivalences;
|
||||
|
||||
/**
|
||||
* Groups of INTERNAL gates that are interchangeable with each other
|
||||
*
|
||||
* E.g: *SYM SYM1
|
||||
* *INT 1 3
|
||||
* *INT 2 5
|
||||
*
|
||||
* The gate described by pins 1 and 3 above, can be swapped internally with the gate decribed
|
||||
* by pins 2 and 5 but they CANNOT be swapped with gates in another part
|
||||
*/
|
||||
std::vector<CADSTAR_SWAP_GROUP> m_InternalSwapGroup;
|
||||
|
||||
/**
|
||||
* Groups of EXTERNAL gates that are interchangeable with each other
|
||||
*
|
||||
* E.g: *SYM SYM2
|
||||
* *EXT 1 3
|
||||
* *EXT 2 5
|
||||
*
|
||||
* The gate described by pins 1 and 3 above, can be swapped internally with the gate decribed
|
||||
* by pins 2 and 5 AND they can be swapped with same gates in another part
|
||||
*/
|
||||
std::vector<CADSTAR_SWAP_GROUP> m_ExternalSwapGroup;
|
||||
|
||||
/**
|
||||
* Star (*) line
|
||||
* *<User-defined name> <Value>
|
||||
* This line is ignored by CADSTAR. Usually they are used by third party tools.
|
||||
* These lines are treated as attributes of the Parts library (i.e. Attribute Type = Parts Library).
|
||||
*/
|
||||
std::map<std::string, std::string> m_UserAttributes;
|
||||
|
||||
/**
|
||||
* Dollar sign ($) line
|
||||
* $[!]<SCM Attribute name>(<Attribute value>)
|
||||
* Attributes related to the schematic symbol.
|
||||
* Is set to read-only if exclamation mark (!) is present
|
||||
*/
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE> m_SchAttributes;
|
||||
|
||||
/**
|
||||
* Percentage sign (%) line
|
||||
* %[!]<PCB Attribute name>(<Attribute value>)
|
||||
* Attributes related to the PCB component / footprint.
|
||||
* Is set to read-only if exclamation mark (!) is present
|
||||
*/
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE> m_PcbAttributes;
|
||||
|
||||
/**
|
||||
* At symbol (@) line
|
||||
* [@[!]<SCM/PCB Attribute name>(<Attribute value>)]
|
||||
* Attributes related to the PCB component AND the schematic symbol.
|
||||
* Is set to read-only if exclamation mark (!) is present
|
||||
*/
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE> m_SchAndPcbAttributes;
|
||||
|
||||
/**
|
||||
* Tilde (~) line
|
||||
* ~[!]<Parts Library Attribute Name>(<Attribute Value>)
|
||||
* Attributes related to the Part itself. It cannot be displayed
|
||||
* on the PCB or schematic but it is used in CADSTAR to search for
|
||||
* parts in the library browser
|
||||
* Is set to read-only if exclamation mark (!) is present
|
||||
*/
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE> m_PartAttributes;
|
||||
};
|
||||
|
||||
|
||||
struct CADSTAR_ATTRIBUTE_VALUE
|
||||
{
|
||||
bool m_ReadOnly = false;
|
||||
std::string m_Value;
|
||||
};
|
||||
|
||||
|
||||
struct CADSTAR_SWAP_GROUP
|
||||
{
|
||||
std::optional<std::string> m_Name;
|
||||
|
||||
/**
|
||||
* Each gate is a list of pin numbers. The order of the pins is important
|
||||
* as it defines the equivalence between gates
|
||||
*/
|
||||
std::vector<std::vector<long>> m_Gates;
|
||||
};
|
||||
|
||||
#endif //CADSTAR_PARTS_LIB_MODEL_H
|
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "cadstar_parts_lib_parser.h"
|
||||
#include "cadstar_parts_lib_grammar.h"
|
||||
|
||||
#include <fmt.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace CADSTAR_PARTS_LIB;
|
||||
|
||||
|
||||
/**
|
||||
* Struture that will be populated by the PEGTL parser
|
||||
*/
|
||||
struct CADSTAR_LIB_PARSER_STATE
|
||||
{
|
||||
std::string m_CurrentString;
|
||||
std::string m_CurrentAttrName;
|
||||
long m_CurrentLong = 0;
|
||||
std::vector<long> m_CurrentPinEquivalenceGroup;
|
||||
std::set<std::string> m_CurrentElementsParsed;
|
||||
bool m_ReadOnly = false;
|
||||
CADSTAR_SWAP_GROUP m_CurrentSwapGroup;
|
||||
CADSTAR_PART_ENTRY m_CurrentPart;
|
||||
CADSTAR_PARTS_LIB_MODEL m_ParsedModel;
|
||||
};
|
||||
|
||||
|
||||
// Default action: Do nothing
|
||||
template <typename Rule>
|
||||
struct CADSTAR_LIB_PARSER_ACTION : tao::pegtl::nothing<Rule>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
long helperStringToLong( std::string aString )
|
||||
{
|
||||
std::stringstream ss( aString );
|
||||
long number;
|
||||
ss >> number;
|
||||
return number;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CONTENT TO NUMBER ACTIONS:
|
||||
// Take the current content string, convert it to a long and store it in StateVariable
|
||||
//
|
||||
#define DEFINE_CONTENT_TO_NUMBER_ACTION( Rule, StateVariable ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
template <typename ActionInput> \
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
||||
s.StateVariable = helperStringToLong( in.string() ); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_CONTENT_TO_NUMBER_ACTION( CURRENT_FORMAT_NUMBER, m_ParsedModel.m_FormatNumber );
|
||||
DEFINE_CONTENT_TO_NUMBER_ACTION( PINNUM, m_CurrentLong );
|
||||
DEFINE_CONTENT_TO_NUMBER_ACTION( MAX_PIN_COUNT, m_CurrentPart.m_MaxPinCount );
|
||||
|
||||
// unfortunately the one below needs to be defined separately
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<EQUIVALENT_PIN>
|
||||
{
|
||||
template <typename ActionInput>
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
||||
s.m_CurrentPinEquivalenceGroup.push_back( helperStringToLong( in.string() ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CONTENT TO CURRENT STRING ACTIONS:
|
||||
// Take the current content string, store it in the state current string
|
||||
//
|
||||
#define DEFINE_CONTENT_TO_STRING_ACTION( Rule ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
template <typename ActionInput> \
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
||||
s.m_CurrentString = in.string(); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_CONTENT_TO_STRING_ACTION( PINNAME );
|
||||
|
||||
//
|
||||
// STRING REPLACEMENT ACTIONS:
|
||||
// Take the current string in the parser state and store it in StateVariable
|
||||
//
|
||||
#define DEFINE_STRING_ACTION( Rule, StateVariable ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
/* @todo : convert to use apply0 to improve performance( once fully tested ) */ \
|
||||
template <typename ActionInput> \
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( in.string().size() >= s.m_CurrentString.size() ); \
|
||||
s.StateVariable = s.m_CurrentString; \
|
||||
s.m_CurrentString = ""; \
|
||||
} \
|
||||
} \
|
||||
|
||||
DEFINE_STRING_ACTION( PART_NAME, m_CurrentPart.m_Name );
|
||||
DEFINE_STRING_ACTION( PART_VERSION, m_CurrentPart.m_Version );
|
||||
DEFINE_STRING_ACTION( PART_NUMBER, m_CurrentPart.m_Number );
|
||||
DEFINE_STRING_ACTION( PART_DESCRIPTION, m_CurrentPart.m_Description );
|
||||
DEFINE_STRING_ACTION( PCB_COMPONENT, m_CurrentPart.m_Pcb_component );
|
||||
DEFINE_STRING_ACTION( PCB_ALTERNATE, m_CurrentPart.m_Pcb_alternate );
|
||||
DEFINE_STRING_ACTION( VALUE, m_CurrentPart.m_Value );
|
||||
DEFINE_STRING_ACTION( DEFINITION_NAME, m_CurrentPart.m_PartDefinitionName );
|
||||
DEFINE_STRING_ACTION( STEM, m_CurrentPart.m_ComponentStem );
|
||||
DEFINE_STRING_ACTION( SYM_ELEMENT_NAME, m_CurrentSwapGroup.m_Name );
|
||||
DEFINE_STRING_ACTION( USER_PART_ATTRIBUTE_NAME, m_CurrentAttrName );
|
||||
DEFINE_STRING_ACTION( ATTRIBUTE_NAME, m_CurrentAttrName );
|
||||
DEFINE_STRING_ACTION( ACCEPTANCE_PART_NAME, m_CurrentPart.m_AcceptancePartName );
|
||||
DEFINE_STRING_ACTION( ACCEPTANCE_TEXT, m_CurrentPart.m_AcceptanceText );
|
||||
DEFINE_STRING_ACTION( SPICE_PART_NAME, m_CurrentPart.m_SpicePartName );
|
||||
|
||||
// Might become m_SpiceModel if SPICE_SECOND is found
|
||||
DEFINE_STRING_ACTION( SPICE_FIRST, m_CurrentPart.m_SpiceValue );
|
||||
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<SPICE_SECOND>
|
||||
{
|
||||
/* @todo : convert to use apply0 to improve performance( once fully tested ) */
|
||||
template <typename ActionInput>
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( in.string().size() >= s.m_CurrentString.size() );
|
||||
s.m_CurrentPart.m_SpiceModel = s.m_CurrentPart.m_SpiceValue; // Parsed by SPICE_FIRST
|
||||
s.m_CurrentPart.m_SpiceValue = s.m_CurrentString;
|
||||
s.m_CurrentString = "";
|
||||
}
|
||||
};
|
||||
|
||||
// STRING SEGMENT action
|
||||
// Any strings we match, append to the current state string (the state string gets
|
||||
// reset after we extract the string to store somewhere else).
|
||||
// The reason we append is because in the fileformat, there can be line continuations,
|
||||
// which we don't want to have in the final string - saves post-processing.
|
||||
template <typename... EXCLUSION_RULES>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<STR_SEGMENT_EXCLUDING<EXCLUSION_RULES...>>
|
||||
{
|
||||
template <typename ActionInput>
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
s.m_CurrentString += in.string();
|
||||
}
|
||||
};
|
||||
|
||||
// PART_ENTRY action
|
||||
// We just push the part to the vector of parts in our state
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<PART_ENTRY>
|
||||
{
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
||||
//Finish the entry
|
||||
s.m_ParsedModel.m_PartEntries.push_back( s.m_CurrentPart );
|
||||
s.m_CurrentPart = CADSTAR_PART_ENTRY();
|
||||
s.m_CurrentElementsParsed.clear();
|
||||
// Todo-we could add progress reporting here?
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<READONLY>
|
||||
{
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
||||
s.m_ReadOnly = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// SINGLE RULE ACTIONS:
|
||||
// Make sure that this rule is only matched once per part and throw a parse error
|
||||
// when this is not the case.
|
||||
//
|
||||
#define DECLARE_SINGLE_MATCH_RULE( Rule, ExtraCode ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
template <typename ActionInput> \
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
||||
\
|
||||
if( s.m_CurrentElementsParsed.count( #Rule ) ) \
|
||||
{ \
|
||||
throw parse_error( #Rule \
|
||||
" was already defined for this part!", \
|
||||
in ); \
|
||||
} \
|
||||
\
|
||||
s.m_CurrentElementsParsed.insert( #Rule ); \
|
||||
ExtraCode; \
|
||||
} \
|
||||
} \
|
||||
|
||||
DECLARE_SINGLE_MATCH_RULE( PART_VALUE, );
|
||||
DECLARE_SINGLE_MATCH_RULE( DFN_LINE, );
|
||||
DECLARE_SINGLE_MATCH_RULE( NGS_LINE, s.m_CurrentPart.m_GateSwappingAllowed = false );
|
||||
DECLARE_SINGLE_MATCH_RULE( NPV_LINE, s.m_CurrentPart.m_PinsVisible = false );
|
||||
DECLARE_SINGLE_MATCH_RULE( STM_LINE, );
|
||||
DECLARE_SINGLE_MATCH_RULE( MXP_LINE, );
|
||||
DECLARE_SINGLE_MATCH_RULE( SPI_LINE, );
|
||||
DECLARE_SINGLE_MATCH_RULE( PAC_LINE, );
|
||||
|
||||
|
||||
//@todo remove once complete
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<UNMATCHED_CONTENT>
|
||||
{
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s ) { s.m_CurrentString = ""; }
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<PINNAME_ENTRY>
|
||||
{
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( s.m_CurrentAttrName == "" );
|
||||
// m_CurrentLong should have been parsed as part of the PINNUM action
|
||||
// m_CurrentString should have been parsed as part of the PINNAME action
|
||||
s.m_CurrentPart.m_PinNamesMap.insert( { s.m_CurrentLong, s.m_CurrentString } );
|
||||
s.m_CurrentString = "";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<PINLABEL_ENTRY>
|
||||
{
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
assert( s.m_CurrentAttrName == "" );
|
||||
// m_CurrentLong should have been parsed as part of the PINNUM action
|
||||
// m_CurrentString should have been parsed as part of the PINLABEL action
|
||||
s.m_CurrentPart.m_PinLabelsMap.insert( { s.m_CurrentLong, s.m_CurrentString } );
|
||||
s.m_CurrentString = "";
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// PIN EQUIVALENCE GROUP ACTIONS:
|
||||
// Take the current m_CurrentPinEquivalenceGroup in the parser state and store it in StateVariable
|
||||
// then clear m_CurrentPinEquivalenceGroup.
|
||||
// Note that m_CurrentPinEquivalenceGroup should have been parsed as part of EQUIVALENT_PIN action
|
||||
//
|
||||
#define DEFINE_PIN_GROUP_ACTION( Rule, StateVariable ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
||||
s.StateVariable.push_back( s.m_CurrentPinEquivalenceGroup ); \
|
||||
s.m_CurrentPinEquivalenceGroup.clear(); \
|
||||
} \
|
||||
} \
|
||||
|
||||
DEFINE_PIN_GROUP_ACTION( EQUIVALENT_PINS_GROUP, m_CurrentPart.m_PinEquivalences );
|
||||
DEFINE_PIN_GROUP_ACTION( INTERNAL_SWAP_GATE, m_CurrentSwapGroup.m_Gates );
|
||||
DEFINE_PIN_GROUP_ACTION( EXTERNAL_SWAP_GATE, m_CurrentSwapGroup.m_Gates );
|
||||
|
||||
|
||||
//
|
||||
// SWAP GROUP ACTIONS:
|
||||
// Take the current m_CurrentSwapGroup in the parser state and store it in StateVariable
|
||||
// then reset m_CurrentSwapGroup.
|
||||
//
|
||||
#define DEFINE_SWAP_GROUP_ACTION( Rule, StateVariable ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
static void apply0( CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
||||
s.StateVariable.push_back( s.m_CurrentSwapGroup ); \
|
||||
s.m_CurrentSwapGroup = CADSTAR_SWAP_GROUP(); \
|
||||
} \
|
||||
} \
|
||||
|
||||
DEFINE_SWAP_GROUP_ACTION( INTERNAL_SWAP_GROUP, m_CurrentPart.m_InternalSwapGroup );
|
||||
DEFINE_SWAP_GROUP_ACTION( EXTERNAL_SWAP_GROUP, m_CurrentPart.m_ExternalSwapGroup );
|
||||
|
||||
|
||||
/**
|
||||
* The format allows user defined "part" attrbutes, but the ones listed here are in-built with
|
||||
* special meaning
|
||||
*/
|
||||
static const std::set<std::string> ReservedWordsStarLines = { "VALUE", "PNM", "PLB", "EQU", "SYM",
|
||||
"INT", "EXT", "DFN", "NGS", "NPV",
|
||||
"STM", "MXP", "SPI", "PAC" };
|
||||
|
||||
template <>
|
||||
struct CADSTAR_LIB_PARSER_ACTION<USER_PART_ATTRIBUTE>
|
||||
{
|
||||
template <typename ActionInput>
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
||||
{
|
||||
if( s.m_CurrentPart.m_UserAttributes.count( s.m_CurrentAttrName ) )
|
||||
{
|
||||
throw parse_error( fmt::format( "Duplicate attribute name '{}'", s.m_CurrentAttrName ),
|
||||
in );
|
||||
}
|
||||
|
||||
if( ReservedWordsStarLines.count( s.m_CurrentAttrName ) )
|
||||
{
|
||||
throw parse_error(
|
||||
fmt::format(
|
||||
"Invalid use of in-built attribute name '{}'. Either the attribute "
|
||||
"was already defined for this part or it has an unexpected syntax.",
|
||||
s.m_CurrentAttrName ),
|
||||
in );
|
||||
}
|
||||
|
||||
s.m_CurrentPart.m_UserAttributes.insert( { s.m_CurrentAttrName, s.m_CurrentString } );
|
||||
s.m_CurrentAttrName = "";
|
||||
s.m_CurrentString = "";
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_ATTRIBUTE_ACTION( Rule, StateVariable ) \
|
||||
template <> \
|
||||
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
||||
{ \
|
||||
template <typename ActionInput> \
|
||||
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
||||
{ \
|
||||
if( s.StateVariable.count( s.m_CurrentAttrName ) ) \
|
||||
{ \
|
||||
throw parse_error( \
|
||||
fmt::format( "Duplicate attribute name '{}'", s.m_CurrentAttrName ), \
|
||||
in ); \
|
||||
} \
|
||||
\
|
||||
CADSTAR_ATTRIBUTE_VALUE val; \
|
||||
val.m_ReadOnly = s.m_ReadOnly; \
|
||||
val.m_Value = s.m_CurrentString; \
|
||||
\
|
||||
s.StateVariable.insert( { s.m_CurrentAttrName, val } ); \
|
||||
s.m_CurrentAttrName = ""; \
|
||||
s.m_CurrentString = ""; \
|
||||
s.m_ReadOnly = false; \
|
||||
} \
|
||||
} \
|
||||
|
||||
DEFINE_ATTRIBUTE_ACTION( SCM_ATTRIBUTE, m_CurrentPart.m_SchAttributes );
|
||||
DEFINE_ATTRIBUTE_ACTION( PCB_ATTRIBUTE, m_CurrentPart.m_PcbAttributes );
|
||||
DEFINE_ATTRIBUTE_ACTION( PART_ATTRIBUTE, m_CurrentPart.m_PartAttributes );
|
||||
DEFINE_ATTRIBUTE_ACTION( SCH_PCB_ATTRIBUTE, m_CurrentPart.m_SchAndPcbAttributes );
|
||||
|
||||
template <typename INPUT_TYPE>
|
||||
bool checkHeaderHelper( INPUT_TYPE& aInput )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( !parse<VALID_HEADER>( aInput ) )
|
||||
return false;
|
||||
}
|
||||
catch( const parse_error& e )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CADSTAR_PARTS_LIB_PARSER::CheckContentHeader( const std::string& aSource ) const
|
||||
{
|
||||
string_input in( aSource, "from_content" );
|
||||
return checkHeaderHelper( in );
|
||||
}
|
||||
|
||||
|
||||
bool CADSTAR_PARTS_LIB_PARSER::CheckFileHeader( const std::filesystem::path& aPath ) const
|
||||
{
|
||||
file_input in( aPath );
|
||||
return checkHeaderHelper( in );
|
||||
}
|
||||
|
||||
|
||||
template<typename INPUT_TYPE>
|
||||
CADSTAR_PARTS_LIB_MODEL readCadstarHelper( INPUT_TYPE& aInput )
|
||||
{
|
||||
CADSTAR_LIB_PARSER_STATE s;
|
||||
|
||||
try
|
||||
{
|
||||
// Todo: We could reserve space for the partEntries vector
|
||||
// to improve performance? E.g.:
|
||||
// s.m_ParsedModel.m_PartEntries.reserve( expectedNumParts );
|
||||
|
||||
if( !parse<GRAMMAR, CADSTAR_LIB_PARSER_ACTION>( aInput, s ) )
|
||||
printf( "Some error occurred!\n" );
|
||||
}
|
||||
catch( const parse_error& e )
|
||||
{
|
||||
const auto p = e.positions().front();
|
||||
std::cerr << "Error at line " << p.line << ", column " << p.column << std::endl
|
||||
<< aInput.line_at( p ) << std::endl
|
||||
<< std::setw( p.column ) << '^' << std::endl
|
||||
<< e.message() << std::endl;
|
||||
}
|
||||
|
||||
return s.m_ParsedModel;
|
||||
}
|
||||
|
||||
|
||||
CADSTAR_PARTS_LIB_MODEL CADSTAR_PARTS_LIB_PARSER::ReadContent( const std::string& aSource ) const
|
||||
{
|
||||
string_input in( aSource, "from_content" );
|
||||
return readCadstarHelper( in );
|
||||
}
|
||||
|
||||
|
||||
CADSTAR_PARTS_LIB_MODEL
|
||||
CADSTAR_PARTS_LIB_PARSER::ReadFile( const std::filesystem::path& aPath ) const
|
||||
{
|
||||
file_input in( aPath );
|
||||
return readCadstarHelper( in );
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CADSTAR_PARTS_LIB_PARSER_H
|
||||
#define CADSTAR_PARTS_LIB_PARSER_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "cadstar_parts_lib_model.h"
|
||||
|
||||
class CADSTAR_PARTS_LIB_PARSER
|
||||
{
|
||||
public:
|
||||
CADSTAR_PARTS_LIB_PARSER(){};
|
||||
~CADSTAR_PARTS_LIB_PARSER(){};
|
||||
|
||||
bool CheckContentHeader( const std::string& aSource ) const;
|
||||
|
||||
bool CheckFileHeader( const std::filesystem::path& aPath ) const;
|
||||
|
||||
bool CheckFileHeader( const std::string& aPath ) const
|
||||
{
|
||||
return CheckFileHeader( std::filesystem::path( aPath ) );
|
||||
};
|
||||
|
||||
|
||||
CADSTAR_PARTS_LIB_MODEL ReadContent( const std::string& aSource ) const;
|
||||
|
||||
CADSTAR_PARTS_LIB_MODEL ReadFile( const std::filesystem::path& aPath ) const;
|
||||
|
||||
CADSTAR_PARTS_LIB_MODEL ReadFile( const std::string& aPath ) const
|
||||
{
|
||||
return ReadFile( std::filesystem::path( aPath ) );
|
||||
};
|
||||
};
|
||||
|
||||
#endif //CADSTAR_PARTS_LIB_PARSER_H
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
|||
|
||||
from math import factorial
|
||||
from itertools import permutations,islice
|
||||
|
||||
with open('cadstarDummy.lib', 'w', newline='\r\n') as f:
|
||||
f.write('# FORMAT 32\n')
|
||||
|
||||
for i in range(100):
|
||||
f.write('\n')
|
||||
f.write(f'.PartName{i} ({i*5}) :2 ;Part {i} Description\n')
|
||||
f.write(f'FOOTPRINT{i} (variant{i*5})\n')
|
||||
|
||||
currentPartData=[]
|
||||
|
||||
currentPartData.append(f'*VALUE {i} uH\n')
|
||||
currentPartData.append(f'*DFN PartName{i}\n')
|
||||
|
||||
if i%10 == 1:
|
||||
currentPartData.append(f'*NGS\n')
|
||||
|
||||
if i%5 == 1:
|
||||
currentPartData.append(f'*NPV\n')
|
||||
|
||||
|
||||
currentPartData.append('*STM L\n')
|
||||
currentPartData.append(f'*MXP {i+10}\n')
|
||||
currentPartData.append(f'*SPI (PartName{i}) {i}uH\n')
|
||||
currentPartData.append(f'*PAC (PartName{i}) Acceptance{i}\n')
|
||||
currentPartData.append(f'*UserFieldpartNo {i*5}\n')
|
||||
currentPartData.append(f'*"UserFieldpartNoCreated by" Person{i}\n')
|
||||
currentPartData.append(f'$"SCH val1" (val{i})\n')
|
||||
currentPartData.append(f'$!SCH val2 (readOnly{i})\n')
|
||||
currentPartData.append(f'%"PCB val1" (val{i})\n')
|
||||
currentPartData.append(f'%!PCB val2 (readOnly{i})\n')
|
||||
currentPartData.append(f'~"Part val1" (val{i})\n')
|
||||
currentPartData.append(f'~!Part val2 (readOnly{i})\n')
|
||||
currentPartData.append(f'@SCH and PCB val1 (val{i})\n')
|
||||
currentPartData.append(f'@!SCH and PCB val2 (readOnly{i})\n')
|
||||
#currentPartData.append(f'Symbol{i}\n')
|
||||
#currentPartData.append('1.0 2.0\n')
|
||||
|
||||
# Change ordering to test parser works
|
||||
nth=(i*101)%factorial(len(currentPartData)) # make a permutation that exists
|
||||
permutatedData=next(islice(permutations(currentPartData), nth, None))
|
||||
|
||||
for data in permutatedData:
|
||||
f.write(data)
|
||||
|
||||
|
||||
f.write('\n.END\n')
|
|
@ -53,6 +53,10 @@ target_link_libraries( qa_utils
|
|||
${LIBBOOST_UNIT_TEST_LIB}
|
||||
)
|
||||
|
||||
# Pass in the default data location
|
||||
set_source_files_properties( wx_utils/unit_test_utils.cpp PROPERTIES
|
||||
COMPILE_DEFINITIONS "QA_EESCHEMA_DATA_LOCATION=(\"${CMAKE_SOURCE_DIR}/qa/data/eeschema\")"
|
||||
)
|
||||
|
||||
target_include_directories( qa_utils PUBLIC
|
||||
include
|
||||
|
|
|
@ -32,9 +32,11 @@
|
|||
#include <qa_utils/wx_utils/wx_assert.h>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
#include <wx/gdicmn.h>
|
||||
|
||||
/**
|
||||
* If HAVE_EXPECTED_FAILURES is defined, this means that
|
||||
* boost::unit_test::expected_failures is available.
|
||||
|
@ -159,6 +161,21 @@ struct print_log_value<std::vector<T>>
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Boost print helper for std::optional
|
||||
*/
|
||||
template <class T>
|
||||
struct print_log_value<std::optional<T>>
|
||||
{
|
||||
inline void operator()( std::ostream& os, std::optional<T> const& aOptional )
|
||||
{
|
||||
if( aOptional.has_value() )
|
||||
print_log_value<T>()( os, aOptional.value() );
|
||||
else
|
||||
os << "nullopt";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Boost print helper for wxPoint. Note operator<< for this type doesn't
|
||||
* exist in non-DEBUG builds.
|
||||
|
@ -168,6 +185,7 @@ struct print_log_value<wxPoint>
|
|||
{
|
||||
void operator()( std::ostream& os, wxPoint const& aVec );
|
||||
};
|
||||
|
||||
}
|
||||
BOOST_TEST_PRINT_NAMESPACE_CLOSE
|
||||
|
||||
|
@ -299,6 +317,16 @@ bool CollectionHasNoDuplicates( const T& aCollection )
|
|||
#define CHECK_WX_ASSERT( STATEMENT )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the configured location of Eeschema test data.
|
||||
*
|
||||
* By default, this is the test data in the source tree, but can be overridden
|
||||
* by the KICAD_TEST_EESCHEMA_DATA_DIR environment variable.
|
||||
*
|
||||
* @return a filename referring to the test data dir to use.
|
||||
*/
|
||||
std::string GetEeschemaTestDataDir();
|
||||
|
||||
} // namespace KI_TEST
|
||||
|
||||
#endif // UNIT_TEST_UTILS__H
|
|
@ -32,4 +32,33 @@ void print_log_value<wxPoint>::operator()( std::ostream& os, wxPoint const& aPt
|
|||
}
|
||||
|
||||
}
|
||||
BOOST_TEST_PRINT_NAMESPACE_CLOSE
|
||||
BOOST_TEST_PRINT_NAMESPACE_CLOSE
|
||||
|
||||
|
||||
|
||||
#ifndef QA_EESCHEMA_DATA_LOCATION
|
||||
#define QA_EESCHEMA_DATA_LOCATION "???"
|
||||
#endif
|
||||
|
||||
std::string KI_TEST::GetEeschemaTestDataDir()
|
||||
{
|
||||
const char* env = std::getenv( "KICAD_TEST_EESCHEMA_DATA_DIR" );
|
||||
std::string fn;
|
||||
|
||||
if( !env )
|
||||
{
|
||||
// Use the compiled-in location of the data dir
|
||||
// (i.e. where the files were at build time)
|
||||
fn = QA_EESCHEMA_DATA_LOCATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use whatever was given in the env var
|
||||
fn = env;
|
||||
}
|
||||
|
||||
// Ensure the string ends in / to force a directory interpretation
|
||||
fn += "/";
|
||||
|
||||
return fn;
|
||||
}
|
|
@ -48,11 +48,6 @@ target_compile_definitions( qa_schematic_utils
|
|||
PUBLIC EESCHEMA
|
||||
)
|
||||
|
||||
# Pass in the default data location
|
||||
set_source_files_properties( schematic_file_util.cpp PROPERTIES
|
||||
COMPILE_DEFINITIONS "QA_EESCHEMA_DATA_LOCATION=(\"${CMAKE_SOURCE_DIR}/qa/data/eeschema\")"
|
||||
)
|
||||
|
||||
target_include_directories( qa_schematic_utils PRIVATE
|
||||
$<TARGET_PROPERTY:eeschema_kiface_objects,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <schematic_file_util.h>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h> // GetEeschemaTestDataDir()
|
||||
|
||||
#include <settings/settings_manager.h>
|
||||
|
||||
|
@ -37,33 +38,6 @@
|
|||
namespace KI_TEST
|
||||
{
|
||||
|
||||
#ifndef QA_EESCHEMA_DATA_LOCATION
|
||||
#define QA_EESCHEMA_DATA_LOCATION "???"
|
||||
#endif
|
||||
|
||||
std::string getEeschemaTestDataDir()
|
||||
{
|
||||
const char* env = std::getenv( "KICAD_TEST_EESCHEMA_DATA_DIR" );
|
||||
std::string fn;
|
||||
|
||||
if( !env )
|
||||
{
|
||||
// Use the compiled-in location of the data dir (i.e. where the files were at build time)
|
||||
fn = QA_EESCHEMA_DATA_LOCATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use whatever was given in the env var
|
||||
fn = env;
|
||||
}
|
||||
|
||||
// Ensure the string ends in / to force a directory interpretation
|
||||
fn += "/";
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
||||
void DumpSchematicToFile( SCHEMATIC& aSchematic, SCH_SHEET& aSheet, const std::string& aFilename )
|
||||
{
|
||||
SCH_SEXPR_PLUGIN io;
|
||||
|
@ -155,7 +129,7 @@ void LoadSchematic( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath
|
|||
aSchematic->Reset();
|
||||
}
|
||||
|
||||
std::string absPath = getEeschemaTestDataDir() + aRelPath.ToStdString();
|
||||
std::string absPath = GetEeschemaTestDataDir() + aRelPath.ToStdString();
|
||||
wxFileName projectFile( absPath + ".kicad_pro" );
|
||||
wxFileName legacyProject( absPath + ".pro" );
|
||||
std::string schematicPath = absPath + ".kicad_sch";
|
||||
|
|
|
@ -52,6 +52,7 @@ set( QA_COMMON_SRCS
|
|||
|
||||
plugins/altium/test_altium_parser.cpp
|
||||
plugins/altium/test_altium_parser_utils.cpp
|
||||
plugins/cadstar/test_cadstar_parts_parser.cpp
|
||||
|
||||
plugins/cadstar/test_cadstar_archive_parser.cpp
|
||||
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022-2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2022-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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
#include <pegtl/contrib/analyze.hpp>
|
||||
#include <pegtl/contrib/trace.hpp>
|
||||
|
||||
// Modules under test:
|
||||
#include <common/plugins/cadstar/cadstar_parts_lib_grammar.h>
|
||||
#include <common/plugins/cadstar/cadstar_parts_lib_parser.h>
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( CadstarPartParser );
|
||||
|
||||
|
||||
static std::string getCadstarTestFile( const std::string& aFile )
|
||||
{
|
||||
return KI_TEST::GetEeschemaTestDataDir() + "/plugins/cadstar/" + aFile;
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( AnalyzeGrammar )
|
||||
{
|
||||
// Verify the grammar has no loops without progress and other issues
|
||||
// See: https://github.com/taocpp/PEGTL/blob/3.2.7/doc/Grammar-Analysis.md
|
||||
const std::size_t grammarIssues = tao::pegtl::analyze<CADSTAR_PARTS_LIB::GRAMMAR>();
|
||||
BOOST_CHECK_EQUAL( grammarIssues, 0 );
|
||||
|
||||
const std::size_t headerIssues = tao::pegtl::analyze<CADSTAR_PARTS_LIB::VALID_HEADER>();
|
||||
BOOST_CHECK_EQUAL( headerIssues, 0 );
|
||||
}
|
||||
|
||||
|
||||
struct CHECK_HEADER_CASE
|
||||
{
|
||||
std::string m_CaseName;
|
||||
std::string m_Content;
|
||||
bool m_ExpectedResult;
|
||||
};
|
||||
|
||||
|
||||
static const std::vector<CHECK_HEADER_CASE> check_header_cases =
|
||||
{
|
||||
{ "1: Normal header", "# Format 32\r\n", true },
|
||||
{ "2: Normal header, extra content", "# Format 32\r\nExtraUnrelatedContent", true },
|
||||
{ "3: Normal header extra spaces (1)", "# Format 32\r\n", true },
|
||||
{ "4: Normal header extra spaces (2)", "# FORMAT 32\r\n", true },
|
||||
{ "5: Normal header on 2nd line", "\r\n# Format 32\r\n", false },
|
||||
{ "6: Normal header prepended", "+# Format 32\r\n", false },
|
||||
{ "7: Normal header prepended spaces", " # Format 32\r\n", false },
|
||||
|
||||
// There appear to be some files on the internet that just don't have a header and
|
||||
// start straight away with the part definitions.
|
||||
{ "8: No header", ".PART-NAME :1 ;Part Descr\r\n", true },
|
||||
{ "9: No header, extra content", ".PART-NAME :1 ;Part Descr\r\nExtra", true },
|
||||
{ "10: No header, on 2nd line", "\r\n.PART-NAME :1 ;Part Descr\r\n", true },
|
||||
{ "11: No header, on 3rd line", "\r\n\r\n.PART-NAME :1 ;Part Descr\r\n", true },
|
||||
{ "12: No header, on 4th line", "\r\n\r\n.PART-NAME :1 ;Part Descr\r\n", true },
|
||||
{ "13: No header, on 4th line", "\r\n\r\n\r\n\r\n.PART-NAME :1 ;P Descr\r\n", true },
|
||||
{ "14: No header, on 5th line", "\r\n\r\n\r\n\r\n\r\n.P-NAME :1 ;PDescr\r\n", true },
|
||||
{ "15: No header, on 6th line", "\r\n\r\n\r\n\r\n\r\n\r\n.P-NAM :1 ;PDes\r\n", false },
|
||||
{ "16: No header, space prepend", " .PART-NAME :1 ;Part Descr\r\n", false },
|
||||
{ "17: No header, spaces & 2nd line", " \r\n.PART-NAME :1 ;Part Descr\r\n", true },
|
||||
{ "18: No header, 2nd line & space", " \r\n .PART-NAME :1 ;Part Descr\r\n", false },
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( CheckHeader )
|
||||
{
|
||||
for( const auto& c : check_header_cases )
|
||||
{
|
||||
BOOST_TEST_INFO_SCOPE( c.m_CaseName );
|
||||
CADSTAR_PARTS_LIB_PARSER p;
|
||||
|
||||
BOOST_CHECK_EQUAL( p.CheckContentHeader( c.m_Content ), c.m_ExpectedResult );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ReadFile )
|
||||
{
|
||||
CADSTAR_PARTS_LIB_PARSER p;
|
||||
|
||||
// Test a programatically generated file (see writeCadstarFile.py)
|
||||
auto ret = p.ReadFile( getCadstarTestFile( "cadstarDummy.lib" ) );
|
||||
|
||||
BOOST_CHECK_EQUAL( ret.m_FormatNumber, 32 );
|
||||
BOOST_CHECK_EQUAL( ret.m_PartEntries.size(), 100 );
|
||||
|
||||
int i = 0;
|
||||
|
||||
for( CADSTAR_PART_ENTRY& partEntry : ret.m_PartEntries )
|
||||
{
|
||||
// Part header
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Name, "PartName" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Number, std::to_string( i * 5 ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Version, std::to_string( 2 ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Description,
|
||||
"Part " + std::to_string( i ) + " Description" );
|
||||
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Pcb_component, "FOOTPRINT" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Pcb_alternate, "variant" + std::to_string( i * 5 ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_Value, std::to_string( i ) + " uH" );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_ComponentStem, "L" );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_MaxPinCount, i + 10 );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_GateSwappingAllowed, i % 10 != 1 );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PinsVisible, i % 5 != 1 );
|
||||
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SpicePartName, "PartName" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SpiceModel, std::optional<std::string>() );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SpiceValue, std::to_string( i ) + "uH" );
|
||||
|
||||
BOOST_CHECK_EQUAL( partEntry.m_AcceptancePartName, "PartName" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_AcceptanceText, "Acceptance" + std::to_string( i ) );
|
||||
|
||||
// User part attributes (* lines)
|
||||
BOOST_CHECK_EQUAL( partEntry.m_UserAttributes["UserFieldpartNo"],
|
||||
std::to_string( i * 5 ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_UserAttributes["UserFieldpartNoCreated by"],
|
||||
"Person" + std::to_string( i ) );
|
||||
|
||||
// SCH attributes ($ lines)
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAttributes["SCH val1"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAttributes["SCH val1"].m_Value,
|
||||
"val" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAttributes["SCH val2"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAttributes["SCH val2"].m_Value,
|
||||
"readOnly" + std::to_string( i ) );
|
||||
|
||||
// PCB attributes (% lines)
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PcbAttributes["PCB val1"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PcbAttributes["PCB val1"].m_Value,
|
||||
"val" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PcbAttributes["PCB val2"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PcbAttributes["PCB val2"].m_Value,
|
||||
"readOnly" + std::to_string( i ) );
|
||||
|
||||
// Parts attributes (~ lines)
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PartAttributes["Part val1"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PartAttributes["Part val1"].m_Value,
|
||||
"val" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PartAttributes["Part val2"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_PartAttributes["Part val2"].m_Value,
|
||||
"readOnly" + std::to_string( i ) );
|
||||
|
||||
// PCB and SCH attributes (@ lines)
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAndPcbAttributes["SCH and PCB val1"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAndPcbAttributes["SCH and PCB val1"].m_Value,
|
||||
"val" + std::to_string( i ) );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAndPcbAttributes["SCH and PCB val2"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( partEntry.m_SchAndPcbAttributes["SCH and PCB val2"].m_Value,
|
||||
"readOnly" + std::to_string( i ) );
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ReadContent )
|
||||
{
|
||||
std::string test =
|
||||
"# Format 32\r\n"
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
" \r\n"
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
"\r\n"
|
||||
".<Part name> (<Part number>):<Part version>;<Description>\r\n"
|
||||
"<PCB Component Refname> (<PCB Alternate Refname>)\r\n"
|
||||
"*VALUE <Value>\r\n"
|
||||
"*PNM 1=A1 2=A2 3=B1 4=B2 5=C1 6=C2\r\n" // <PinId>=<Pinname> <PinId>=<Pinname> etc
|
||||
"*PLB 1=\"VCC\" 2=\"GND\" 3=\"'EN\" 4=\"OUT\" 5=\"OUT\" 6=\"IN\"\r\n" // <id>=<label>
|
||||
"*EQU 4=5, 6=7=8, 9=10=11\r\n" // <PinId>=<PinId>=<PinId> <PinId>=<PinId> etc ...
|
||||
"*SYM Group1\r\n"
|
||||
"*INT 4 5\r\n"
|
||||
"*INT 6 7\r\n"
|
||||
"*SYM Group2\r\n"
|
||||
"*EXT 1 2\r\n"
|
||||
"*EXT 4 7\r\n"
|
||||
"*DFN <Definition name>\r\n"
|
||||
"*NGS\r\n"
|
||||
"*NPV\r\n"
|
||||
"*STM <Component name stem>\r\n"
|
||||
"*MXP 32\r\n" //<Maximum number of connector pins>
|
||||
"*SPI (<Part name>) <Model> <Value>\r\n"
|
||||
"*PAC (<Part name>) <Acceptance Text>\r\n"
|
||||
"*userAttribute userAttributeVal\r\n"
|
||||
"*\"User spaced name\" userSpacedAttributeVal\r\n"
|
||||
"$<SCM Attribute name1>(<Attribute value for name1>)\r\n"
|
||||
"$!<SCM Attribute name2>(\"<Attribute value for name2>\")\r\n"
|
||||
"%<PCB Attribute name1>(\"<Attribute value1>\")\r\n"
|
||||
"%!\"<PCB Attribute name2>\"(<Attribute value2>)\r\n"
|
||||
"~<Parts Attribute name1>(<Attribute value1>)\r\n"
|
||||
"~!<Parts Attribute name2>(<Attribute value2>)\r\n"
|
||||
"@<SCM/PCB Attribute name1>(<Attribute value1>)\r\n"
|
||||
"@!<SCM/PCB Attribute name2>(<Attribute value2>)\r\n";
|
||||
//"etc ...\r\n"
|
||||
//"<SCM Symbol Refname> (<SCM Alternate Refname>)\r\n"
|
||||
//"<PinIdentifier>.<Position> !<Pintype> :<Loading> etc\r\n"
|
||||
//"<PinIdentifier>.<Position> !<Pintype> :<Loading> etc ...\r\n"
|
||||
//"etc ...\r\n"
|
||||
//"/<Signame> <PinIdentifier>.<Position>!<Pintype>:<Loading>\r\n"
|
||||
//"/<Signame> <PinIdentifier>.<Position>!<Pintype>:<Loading>\r\n";
|
||||
|
||||
CADSTAR_PARTS_LIB_PARSER csParser;
|
||||
CADSTAR_PARTS_LIB_MODEL result = csParser.ReadContent( test );
|
||||
|
||||
std::optional<std::string> nullOptString;
|
||||
|
||||
BOOST_CHECK_EQUAL( result.m_FormatNumber, 32 );
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries.size(), 1 );
|
||||
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Name, "<Part name>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Number, "<Part number>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Version, "<Part version>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Description, "<Description>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Pcb_component, "<PCB Component Refname>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Pcb_alternate, "<PCB Alternate Refname>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_Value, "<Value>" );
|
||||
|
||||
// Check pin names (*PNM)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_PinNamesMap.size(), 6 );
|
||||
|
||||
std::map<long, std::string>& pinNames = result.m_PartEntries[0].m_PinNamesMap;
|
||||
BOOST_CHECK_EQUAL( pinNames[1], "A1" );
|
||||
BOOST_CHECK_EQUAL( pinNames[2], "A2" );
|
||||
BOOST_CHECK_EQUAL( pinNames[3], "B1" );
|
||||
BOOST_CHECK_EQUAL( pinNames[4], "B2" );
|
||||
BOOST_CHECK_EQUAL( pinNames[5], "C1" );
|
||||
BOOST_CHECK_EQUAL( pinNames[6], "C2" );
|
||||
|
||||
// Check pin labels (*PLB)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_PinLabelsMap.size(), 6 );
|
||||
|
||||
std::map<long, std::string>& pinlabels = result.m_PartEntries[0].m_PinLabelsMap;
|
||||
BOOST_CHECK_EQUAL( pinlabels[1], "VCC" );
|
||||
BOOST_CHECK_EQUAL( pinlabels[2], "GND" );
|
||||
BOOST_CHECK_EQUAL( pinlabels[3], "'EN" );
|
||||
BOOST_CHECK_EQUAL( pinlabels[4], "OUT" );
|
||||
BOOST_CHECK_EQUAL( pinlabels[5], "OUT" );
|
||||
BOOST_CHECK_EQUAL( pinlabels[6], "IN" );
|
||||
|
||||
// Check pin equivalences (*EQU)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_PinEquivalences.size(), 3 );
|
||||
|
||||
std::vector<std::vector<long>>& pinEqus = result.m_PartEntries[0].m_PinEquivalences;
|
||||
BOOST_REQUIRE_EQUAL( pinEqus[0].size(), 2 );
|
||||
BOOST_REQUIRE_EQUAL( pinEqus[1].size(), 3 );
|
||||
BOOST_REQUIRE_EQUAL( pinEqus[2].size(), 3 );
|
||||
|
||||
BOOST_CHECK_EQUAL( pinEqus[0][0], 4 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[0][1], 5 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[1][0], 6 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[1][1], 7 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[1][2], 8 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[2][0], 9 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[2][1], 10 );
|
||||
BOOST_CHECK_EQUAL( pinEqus[2][2], 11 );
|
||||
|
||||
// Check internal swap groups equivalences (*INT)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_InternalSwapGroup.size(), 1 );
|
||||
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_InternalSwapGroup[0].m_Name, "Group1" );
|
||||
|
||||
std::vector<std::vector<long>>& intgates =
|
||||
result.m_PartEntries[0].m_InternalSwapGroup[0].m_Gates;
|
||||
|
||||
BOOST_REQUIRE_EQUAL( intgates[0].size(), 2 );
|
||||
BOOST_REQUIRE_EQUAL( intgates[1].size(), 2 );
|
||||
|
||||
BOOST_CHECK_EQUAL( intgates[0][0], 4 );
|
||||
BOOST_CHECK_EQUAL( intgates[0][1], 5 );
|
||||
BOOST_CHECK_EQUAL( intgates[1][0], 6 );
|
||||
BOOST_CHECK_EQUAL( intgates[1][1], 7 );
|
||||
|
||||
// Check external swap groups equivalences (*EXT)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_ExternalSwapGroup.size(), 1 );
|
||||
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_ExternalSwapGroup[0].m_Name, "Group2" );
|
||||
|
||||
std::vector<std::vector<long>>& extgates =
|
||||
result.m_PartEntries[0].m_ExternalSwapGroup[0].m_Gates;
|
||||
|
||||
BOOST_REQUIRE_EQUAL( extgates[0].size(), 2 );
|
||||
BOOST_REQUIRE_EQUAL( extgates[1].size(), 2 );
|
||||
|
||||
BOOST_CHECK_EQUAL( extgates[0][0], 1 );
|
||||
BOOST_CHECK_EQUAL( extgates[0][1], 2 );
|
||||
BOOST_CHECK_EQUAL( extgates[1][0], 4 );
|
||||
BOOST_CHECK_EQUAL( extgates[1][1], 7 );
|
||||
|
||||
// Check part Definition
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_PartDefinitionName, "<Definition name>" );
|
||||
|
||||
// Check *NGS
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_GateSwappingAllowed, false );
|
||||
|
||||
// Check *NPV
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_PinsVisible, false );
|
||||
|
||||
// Check *STM
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_ComponentStem, "<Component name stem>" );
|
||||
|
||||
// Check *MXP
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_MaxPinCount, 32 );
|
||||
|
||||
// Check *SPI
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_SpicePartName, "<Part name>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_SpiceModel, "<Model>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_SpiceValue, "<Value>" );
|
||||
|
||||
// Check *PAC
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_AcceptancePartName, "<Part name>" );
|
||||
BOOST_CHECK_EQUAL( result.m_PartEntries[0].m_AcceptanceText, "<Acceptance Text>" );
|
||||
|
||||
// Check user attributes (* lines)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_UserAttributes.size(), 2 );
|
||||
|
||||
std::map<std::string, std::string>& userAtts = result.m_PartEntries[0].m_UserAttributes;
|
||||
BOOST_CHECK_EQUAL( userAtts["userAttribute"], "userAttributeVal" );
|
||||
BOOST_CHECK_EQUAL( userAtts["User spaced name"], "userSpacedAttributeVal" );
|
||||
|
||||
// Check SCH attributes ($ lines)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_SchAttributes.size(), 2 );
|
||||
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE>& schAtts =
|
||||
result.m_PartEntries[0].m_SchAttributes;
|
||||
|
||||
BOOST_CHECK_EQUAL( schAtts["<SCM Attribute name1>"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( schAtts["<SCM Attribute name1>"].m_Value, "<Attribute value for name1>" );
|
||||
|
||||
BOOST_CHECK_EQUAL( schAtts["<SCM Attribute name2>"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( schAtts["<SCM Attribute name2>"].m_Value, "<Attribute value for name2>" );
|
||||
|
||||
// Check PCB attributes (% lines)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_PcbAttributes.size(), 2 );
|
||||
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE>& pcbAtts =
|
||||
result.m_PartEntries[0].m_PcbAttributes;
|
||||
|
||||
BOOST_CHECK_EQUAL( pcbAtts["<PCB Attribute name1>"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( pcbAtts["<PCB Attribute name1>"].m_Value, "<Attribute value1>" );
|
||||
|
||||
BOOST_CHECK_EQUAL( pcbAtts["<PCB Attribute name2>"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( pcbAtts["<PCB Attribute name2>"].m_Value, "<Attribute value2>" );
|
||||
|
||||
// Check Part attributes (~ lines)
|
||||
BOOST_REQUIRE_EQUAL( result.m_PartEntries[0].m_PartAttributes.size(), 2 );
|
||||
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE>& partAtts =
|
||||
result.m_PartEntries[0].m_PartAttributes;
|
||||
|
||||
BOOST_CHECK_EQUAL( partAtts["<Parts Attribute name1>"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( partAtts["<Parts Attribute name1>"].m_Value, "<Attribute value1>" );
|
||||
|
||||
BOOST_CHECK_EQUAL( partAtts["<Parts Attribute name2>"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( partAtts["<Parts Attribute name2>"].m_Value, "<Attribute value2>" );
|
||||
|
||||
// Check Compbined Sch/PCB attributes (@ lines)
|
||||
std::map<std::string, CADSTAR_ATTRIBUTE_VALUE>schAndPcbAtts =
|
||||
result.m_PartEntries[0].m_SchAndPcbAttributes;
|
||||
|
||||
BOOST_CHECK_EQUAL( schAndPcbAtts["<SCM/PCB Attribute name1>"].m_ReadOnly, false );
|
||||
BOOST_CHECK_EQUAL( schAndPcbAtts["<SCM/PCB Attribute name1>"].m_Value, "<Attribute value1>" );
|
||||
|
||||
BOOST_CHECK_EQUAL( schAndPcbAtts["<SCM/PCB Attribute name2>"].m_ReadOnly, true );
|
||||
BOOST_CHECK_EQUAL( schAndPcbAtts["<SCM/PCB Attribute name2>"].m_Value, "<Attribute value2>" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -151,10 +151,5 @@ target_compile_definitions( qa_eeschema
|
|||
PUBLIC EESCHEMA
|
||||
)
|
||||
|
||||
# Pass in the default data location
|
||||
set_source_files_properties( eeschema_test_utils.cpp PROPERTIES
|
||||
COMPILE_DEFINITIONS "QA_EESCHEMA_DATA_LOCATION=(\"${CMAKE_SOURCE_DIR}/qa/data/eeschema\")"
|
||||
)
|
||||
|
||||
kicad_add_boost_test( qa_eeschema qa_eeschema )
|
||||
|
||||
|
|
|
@ -34,34 +34,6 @@
|
|||
#include <eeschema/connection_graph.h>
|
||||
|
||||
|
||||
#ifndef QA_EESCHEMA_DATA_LOCATION
|
||||
#define QA_EESCHEMA_DATA_LOCATION "???"
|
||||
#endif
|
||||
|
||||
wxFileName KI_TEST::GetEeschemaTestDataDir()
|
||||
{
|
||||
const char* env = std::getenv( "KICAD_TEST_EESCHEMA_DATA_DIR" );
|
||||
wxString fn;
|
||||
|
||||
if( !env )
|
||||
{
|
||||
// Use the compiled-in location of the data dir
|
||||
// (i.e. where the files were at build time)
|
||||
fn << QA_EESCHEMA_DATA_LOCATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use whatever was given in the env var
|
||||
fn << env;
|
||||
}
|
||||
|
||||
// Ensure the string ends in / to force a directory interpretation
|
||||
fn << "/";
|
||||
|
||||
return wxFileName{ fn };
|
||||
}
|
||||
|
||||
|
||||
void KI_TEST::SCHEMATIC_TEST_FIXTURE::LoadSchematic( const wxString& aBaseName )
|
||||
{
|
||||
wxFileName fn = GetSchematicPath( aBaseName );
|
||||
|
@ -122,7 +94,7 @@ void KI_TEST::SCHEMATIC_TEST_FIXTURE::LoadSchematic( const wxString& aBaseName )
|
|||
|
||||
wxFileName KI_TEST::SCHEMATIC_TEST_FIXTURE::GetSchematicPath( const wxString& aBaseName )
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "netlists" );
|
||||
fn.AppendDir( aBaseName );
|
||||
fn.SetName( aBaseName );
|
||||
|
|
|
@ -44,16 +44,6 @@
|
|||
|
||||
namespace KI_TEST
|
||||
{
|
||||
/**
|
||||
* Get the configured location of Eeschema test data.
|
||||
*
|
||||
* By default, this is the test data in the source tree, but can be overridden
|
||||
* by the KICAD_TEST_EESCHEMA_DATA_DIR environment variable.
|
||||
*
|
||||
* @return a filename referring to the test data dir to use.
|
||||
*/
|
||||
wxFileName GetEeschemaTestDataDir();
|
||||
|
||||
/**
|
||||
* A generic fixture for loading schematics and associated settings for qa tests
|
||||
*/
|
||||
|
|
|
@ -35,7 +35,7 @@ class TEST_SIM_LIBRARY_SPICE_FIXTURE
|
|||
public:
|
||||
std::string GetLibraryPath( const std::string& aBaseName )
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "spice_netlists" );
|
||||
fn.AppendDir( "libraries" );
|
||||
fn.SetName( aBaseName );
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
|
||||
wxFileName GetSchematicPath( const wxString& aBaseName ) override
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.SetName( aBaseName );
|
||||
fn.SetExt( KiCadSchematicFileExtension );
|
||||
|
||||
|
|
|
@ -46,8 +46,9 @@ BOOST_AUTO_TEST_CASE( FindPlugin )
|
|||
*/
|
||||
static wxFileName getEagleTestSchematic( const wxString& sch_file )
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
fn.AppendDir( "eagle_schematics" );
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "plugins" );
|
||||
fn.AppendDir( "eagle" );
|
||||
fn.SetFullName( sch_file );
|
||||
|
||||
return fn;
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
|
||||
wxFileName GetSchematicPath( const wxString& aBaseName ) override
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "spice_netlists" );
|
||||
fn.AppendDir( aBaseName );
|
||||
fn.SetName( aBaseName );
|
||||
|
|
|
@ -32,7 +32,7 @@ protected:
|
|||
|
||||
wxFileName TEST_SCH_SHEET_LIST_FIXTURE::GetSchematicPath( const wxString& aRelativePath )
|
||||
{
|
||||
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "netlists" );
|
||||
|
||||
wxString path = fn.GetFullPath();
|
||||
|
|
Loading…
Reference in New Issue