Add CADSTAR Parts Library (.lib) parser and qa tests

This commit is contained in:
Roberto Fernandez Bautista 2022-12-04 16:01:19 +01:00
parent e51594cdf5
commit 379e3b2fbb
24 changed files with 3662 additions and 84 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 );
}

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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>
)

View File

@ -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";

View File

@ -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

View File

@ -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()

View File

@ -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 )

View File

@ -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 );

View File

@ -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
*/

View File

@ -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 );

View File

@ -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 );

View File

@ -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;

View File

@ -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 );

View File

@ -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();