Skip to content

Commit 919f2e6

Browse files
bgn42jkrechCopilot
authored
Issue#129 (#237)
* added unittest for strip pName/vendor and minor changes * Delete testdata/testExamples/STM32F2/out/CubeMX/STM32F217IGHx/Debug/CubeMX.Debug+STM32F217IGHx.cbuild.yml Depending on the call the tests require the generator variants of cbuild-idx and cbuild from the tmp directory but not the ones from out. * Delete testdata/testExamples/STM32F2/.clangd * Delete testdata/testExamples/STM32F2/out/CubeMX+STM32F217IGHx.cbuild-run.yml * Delete testdata/testExamples/STM32F2/CubeMX.cbuild-set.yml * Delete testdata/testExamples/STM32F2/CubeMX.cbuild-pack.yml * Delete testdata/testExamples/STM32F2/RTE/_Debug_STM32F217IGHx/RTE_Components.h * Delete testdata/testExamples/STM32F2/CubeMX.cbuild-idx.yml * inplemented fix for issue #129 and added a big unit test for different possible .mxproject content * Crazy golangcilint forced me to name a variable and struct with other case than the values it will contain. so I'll try another crazy name. * two german comments translated * corrected path calculation of ThirdParty source files * Simplyfied option use for "read"-functionality. Separate name of third party part from vendor and version creating multiple groups. Removed filter of file names from third party files. Changed filter "system_" to "system_stm32" * renamed ...Ip... to ... Iq... because golangci flags a name with ...Ip... as an error. * Update internal/readFile/readFile.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Joachim Krech <8290187+jkrech@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 0c2491c commit 919f2e6

11 files changed

Lines changed: 983 additions & 10 deletions

File tree

internal/common/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func ReadYml(path string, out interface{}) error {
1919
yamlFile, err := os.ReadFile(path)
2020
if err != nil {
2121
log.Errorf("yamlFile.Get err %v ", err)
22+
return err
2223
}
2324
err = yaml.Unmarshal(yamlFile, out)
2425
if err != nil {

internal/readFile/readFile.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ func Process(inFile, inFile2, outPath string) error {
2626
var cbuildParams cbuild.ParamsType
2727
var params []stm32cubemx.BridgeParamType
2828

29-
if strings.Contains(inFile, "cbuild-gen-idx.yml") {
30-
err := cbuild.Read(inFile, "CubeMX", &cbuildParams)
29+
var genIdxFile string
30+
if strings.Contains(inFile, "cbuild-gen-idx.yml") { // -f
31+
genIdxFile = inFile
32+
}
33+
if strings.Contains(inFile2, "cbuild-gen-idx.yml") { // -r
34+
genIdxFile = inFile2
35+
}
36+
if len(genIdxFile) > 0 {
37+
err := cbuild.Read(genIdxFile, "CubeMX", &cbuildParams)
3138
if err != nil {
3239
return err
3340
}
@@ -44,10 +51,10 @@ func Process(inFile, inFile2, outPath string) error {
4451
}
4552

4653
var mxprojectFile string
47-
if strings.Contains(inFile, ".mxproject") {
54+
if strings.Contains(inFile, ".mxproject") { // -f
4855
mxprojectFile = inFile
4956
}
50-
if strings.Contains(inFile2, ".mxproject") {
57+
if strings.Contains(inFile2, ".mxproject") { // -r
5158
mxprojectFile = inFile2
5259
}
5360

@@ -84,7 +91,8 @@ func Process(inFile, inFile2, outPath string) error {
8491
return err
8592
}
8693

87-
err = stm32cubemx.ReadContexts(workDir+"/STM32CubeMX/STM32CubeMX.ioc", params)
94+
// err = stm32cubemx.ReadContexts(workDir+"/STM32CubeMX/STM32CubeMX.ioc", params)
95+
err = stm32cubemx.ReadContexts(filepath.Join(workDir, "STM32CubeMX.ioc"), params)
8896
if err != nil {
8997
return err
9098
}

internal/stm32CubeMX/iniReader.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ type MxprojectAllType struct {
2323
Mxproject []MxprojectType
2424
}
2525

26+
type ThirdPartyIqNames struct { // crazy golangci does not allow me to name it ...IpNames
27+
ThirdPartyIqName string
28+
IncludeFiles []string
29+
SourceAsmFiles []string
30+
SourceFiles []string
31+
}
32+
2633
type MxprojectType struct {
2734
Context string
2835
PreviousLibFiles struct {
@@ -42,6 +49,7 @@ type MxprojectType struct {
4249
SourcePathList []string
4350
SourceFiles string
4451
}
52+
ThirdPartyIqFiles []ThirdPartyIqNames
4553
}
4654

4755
type IniSectionsType struct {
@@ -193,10 +201,56 @@ func GetSections(inidata *ini.File, iniSections *[]IniSectionsType) error {
193201
return nil
194202
}
195203

204+
func removeVendorAndVersion(ipName string) string {
205+
parts := strings.Split(ipName, ".")
206+
if len(parts) > 1 {
207+
return parts[1]
208+
}
209+
return ipName
210+
}
211+
196212
func GetData(inidata *ini.File, iniName string, compiler string) (MxprojectType, error) {
197213
var mxproject MxprojectType
198214
var sectionName string
199215
var PreviousUsedFilesID string
216+
var section *ini.Section
217+
218+
const ThirdPartyIqID = "ThirdPartyIp" // golangcilint forced me to name it IPID but that would be wrong so another try
219+
if iniName != "" {
220+
sectionName = iniName + ":" + ThirdPartyIqID
221+
} else {
222+
sectionName = ThirdPartyIqID
223+
}
224+
section = inidata.Section(sectionName)
225+
if section != nil {
226+
var ipNames []string
227+
ipNumber := section.Key("ThirdPartyIpNumber").String()
228+
ipCnt, _ := strconv.Atoi(ipNumber)
229+
for cnt := 0; cnt < ipCnt; cnt++ {
230+
ipName := section.Key("ThirdPartyIpName#" + strconv.Itoa(cnt)).String()
231+
if ipName != "" {
232+
ipNames = append(ipNames, ipName)
233+
}
234+
}
235+
for _, ipName := range ipNames {
236+
fullIqName := "ThirdPartyIp#" + ipName // crazy golangci does not allow me to name it fullIpName
237+
if iniName != "" {
238+
sectionName = iniName + ":" + fullIqName
239+
} else {
240+
sectionName = fullIqName
241+
}
242+
ipName = removeVendorAndVersion(ipName)
243+
section = inidata.Section(sectionName)
244+
if section != nil {
245+
var tpip ThirdPartyIqNames
246+
tpip.ThirdPartyIqName = ipName
247+
StoreItemCsv(&tpip.IncludeFiles, section, "include")
248+
StoreItemCsv(&tpip.SourceAsmFiles, section, "sourceAsm")
249+
StoreItemCsv(&tpip.SourceFiles, section, "source")
250+
mxproject.ThirdPartyIqFiles = append(mxproject.ThirdPartyIqFiles, tpip)
251+
}
252+
}
253+
}
200254

201255
PreviousUsedFilesID, err := GetPreviousUsedFilesID(compiler)
202256
if err != nil {
@@ -208,7 +262,7 @@ func GetData(inidata *ini.File, iniName string, compiler string) (MxprojectType,
208262
} else {
209263
sectionName = PreviousUsedFilesID
210264
}
211-
section := inidata.Section(sectionName)
265+
section = inidata.Section(sectionName)
212266
if section != nil {
213267
StoreItemCsv(&mxproject.PreviousUsedFiles.SourceFiles, section, "SourceFiles")
214268
StoreItemCsv(&mxproject.PreviousUsedFiles.HeaderPath, section, "HeaderPath")

internal/stm32CubeMX/iniReader_test.go

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66

77
package stm32cubemx
88

9+
import (
10+
"os"
11+
"path/filepath"
12+
"reflect"
13+
"testing"
14+
15+
"gopkg.in/ini.v1"
16+
)
17+
918
func ExamplePrintKeyValStr() {
1019
PrintKeyValStr("key", "val")
1120
// Output:
@@ -28,3 +37,220 @@ func ExamplePrintKeyValInt() {
2837
//
2938
// key : 4711
3039
}
40+
41+
// Test_GetData verifies parsing of different sections (.mxproject logic)
42+
func Test_GetData(t *testing.T) {
43+
t.Parallel()
44+
45+
// Helper function to write a temporary INI file
46+
writeIni := func(t *testing.T, content string) *ini.File {
47+
t.Helper()
48+
tmp := filepath.Join(t.TempDir(), "test.mxproject")
49+
if err := os.WriteFile(tmp, []byte(content), 0o600); err != nil {
50+
t.Fatalf("failed writing tmp ini: %v", err)
51+
}
52+
defer func() {
53+
_ = os.Remove(tmp)
54+
}()
55+
inidata, err := ini.Load(tmp)
56+
if err != nil {
57+
t.Fatalf("failed loading ini: %v", err)
58+
}
59+
return inidata
60+
}
61+
62+
iniFull := `
63+
[Ctx1:ThirdPartyIp]
64+
ThirdPartyIpNumber=2
65+
ThirdPartyIpName#0=IPX
66+
ThirdPartyIpName#1=IPY
67+
68+
[Ctx1:ThirdPartyIp#IPX]
69+
include=inc1 ;inc2;inc3
70+
sourceAsm=asm1 ;asm2
71+
source=ipx_src1.c ;ipx_src2.c
72+
73+
[Ctx1:ThirdPartyIp#IPY]
74+
include=incY1 ;incY2
75+
source=ipy_src.c ;ipy_src_more.c
76+
77+
[Ctx1:PreviousUsedCubeIDEFiles]
78+
SourceFiles=src1.c ;src2.c;src3.c
79+
HeaderPath=./include ;./inc2;./inc3
80+
CDefines=DEF1 ;DEF_TWO;DEF_THREE
81+
82+
[Ctx1:PreviousLibFiles]
83+
LibFiles=libA.a ;libB.a
84+
85+
[Ctx1:PreviousGenFiles]
86+
AdvancedFolderStructure=1
87+
HeaderFileListSize=2
88+
HeaderFiles#0=hf0.h
89+
HeaderFiles#1=hf1.h
90+
HeaderFolderListSize=1
91+
HeaderPath#0=./gen/inc
92+
HeaderFiles=headers.h
93+
SourceFileListSize=1
94+
SourceFiles#0=sf0.c
95+
SourceFolderListSize=1
96+
SourcePath#0=./gen/src
97+
SourceFiles=sfMain.c
98+
`
99+
100+
iniNoCtx := `
101+
[ThirdPartyIp]
102+
ThirdPartyIpNumber=1
103+
ThirdPartyIpName#0=LIB
104+
105+
[ThirdPartyIp#LIB]
106+
include=lib_inc ;lib_extra
107+
sourceAsm=lib_startup.s
108+
source=lib_src.c ;lib_more.c
109+
110+
[PreviousUsedKeilFiles]
111+
SourceFiles=main.c ;utils.c
112+
HeaderPath=./inc ;./inc2
113+
CDefines=KEIL_DEF ;OTHER
114+
`
115+
116+
tests := []struct {
117+
name string
118+
inidata *ini.File
119+
ctx string
120+
compiler string
121+
wantErr bool
122+
check func(t *testing.T, mx MxprojectType)
123+
}{
124+
{
125+
name: "context_gcc_full_sections",
126+
inidata: writeIni(t, iniFull),
127+
ctx: "Ctx1",
128+
compiler: "GCC",
129+
wantErr: false,
130+
check: func(t *testing.T, mx MxprojectType) {
131+
// ThirdPartyIpFiles structure changed: now slice of ThirdPartyIpNames
132+
var includes, asms, sources []string
133+
var names []string
134+
for _, ip := range mx.ThirdPartyIqFiles {
135+
includes = append(includes, ip.IncludeFiles...)
136+
asms = append(asms, ip.SourceAsmFiles...)
137+
sources = append(sources, ip.SourceFiles...)
138+
names = append(names, ip.ThirdPartyIqName)
139+
}
140+
if !containsAll(names, []string{"IPX", "IPY"}) {
141+
t.Errorf("expected IP names IPX/IPY got %v", names)
142+
}
143+
if !containsAll(includes, []string{"inc1", "inc2", "inc3", "incY1", "incY2"}) {
144+
t.Errorf("expected all include files, got: %v", includes)
145+
}
146+
if !containsAll(asms, []string{"asm1", "asm2"}) { // IPY has no sourceAsm
147+
t.Errorf("expected asm1/asm2 in SourceAsmFiles: %v", asms)
148+
}
149+
if !containsAll(sources, []string{"ipx_src1.c", "ipx_src2.c", "ipy_src.c", "ipy_src_more.c"}) {
150+
t.Errorf("third-party source files incomplete: %v", sources)
151+
}
152+
// PreviousUsedFiles
153+
expSrc := []string{"src1.c", "src2.c", "src3.c"}
154+
if !reflect.DeepEqual(mx.PreviousUsedFiles.SourceFiles, expSrc) {
155+
t.Errorf("SourceFiles expected %v got %v", expSrc, mx.PreviousUsedFiles.SourceFiles)
156+
}
157+
expInc := []string{"./include", "./inc2", "./inc3"}
158+
if !reflect.DeepEqual(mx.PreviousUsedFiles.HeaderPath, expInc) {
159+
t.Errorf("HeaderPath expected %v got %v", expInc, mx.PreviousUsedFiles.HeaderPath)
160+
}
161+
expDef := []string{"DEF1", "DEF_TWO", "DEF_THREE"}
162+
if !reflect.DeepEqual(mx.PreviousUsedFiles.CDefines, expDef) {
163+
t.Errorf("CDefines expected %v got %v", expDef, mx.PreviousUsedFiles.CDefines)
164+
}
165+
// PreviousLibFiles
166+
if !reflect.DeepEqual(mx.PreviousLibFiles.LibFiles, []string{"libA.a", "libB.a"}) {
167+
t.Errorf("LibFiles mismatch: %v", mx.PreviousLibFiles.LibFiles)
168+
}
169+
// PreviousGenFiles (only sample check)
170+
if mx.PreviousGenFiles.AdvancedFolderStructure != "1" {
171+
t.Errorf("AdvancedFolderStructure expected '1' got %v", mx.PreviousGenFiles.AdvancedFolderStructure)
172+
}
173+
if !containsAll(mx.PreviousGenFiles.HeaderFilesList, []string{"hf0.h", "hf1.h"}) {
174+
t.Errorf("HeaderFilesList missing entries: %v", mx.PreviousGenFiles.HeaderFilesList)
175+
}
176+
if !containsAll(mx.PreviousGenFiles.SourceFilesList, []string{"sf0.c"}) {
177+
t.Errorf("SourceFilesList expected sf0.c: %v", mx.PreviousGenFiles.SourceFilesList)
178+
}
179+
if mx.PreviousGenFiles.SourceFiles != "sfMain.c" {
180+
t.Errorf("single SourceFiles expected sfMain.c got %v", mx.PreviousGenFiles.SourceFiles)
181+
}
182+
},
183+
},
184+
{
185+
name: "no_context_keil",
186+
inidata: writeIni(t, iniNoCtx),
187+
ctx: "",
188+
compiler: "AC6",
189+
wantErr: false,
190+
check: func(t *testing.T, mx MxprojectType) {
191+
var includes []string
192+
for _, ip := range mx.ThirdPartyIqFiles {
193+
includes = append(includes, ip.IncludeFiles...)
194+
}
195+
if !containsAll(includes, []string{"lib_inc", "lib_extra"}) {
196+
t.Errorf("IncludeFiles expected lib_inc/lib_extra: %v", includes)
197+
}
198+
if !containsAll(mx.PreviousUsedFiles.SourceFiles, []string{"main.c", "utils.c"}) {
199+
t.Errorf("SourceFiles expected main.c/utils.c: %v", mx.PreviousUsedFiles.SourceFiles)
200+
}
201+
if !containsAll(mx.PreviousUsedFiles.CDefines, []string{"KEIL_DEF", "OTHER"}) {
202+
t.Errorf("CDefines expected KEIL_DEF/OTHER: %v", mx.PreviousUsedFiles.CDefines)
203+
}
204+
},
205+
},
206+
{
207+
name: "unknown_compiler_error",
208+
inidata: writeIni(t, iniFull),
209+
ctx: "Ctx1",
210+
compiler: "UNKNOWN",
211+
wantErr: true,
212+
check: func(t *testing.T, mx MxprojectType) {},
213+
},
214+
{
215+
name: "empty_ini_no_sections",
216+
inidata: writeIni(t, ""),
217+
ctx: "Ctx1",
218+
compiler: "GCC",
219+
wantErr: false,
220+
check: func(t *testing.T, mx MxprojectType) {
221+
if len(mx.PreviousUsedFiles.SourceFiles) != 0 || len(mx.ThirdPartyIqFiles) != 0 {
222+
t.Errorf("expected empty arrays/slices for missing sections, got %+v", mx)
223+
}
224+
},
225+
},
226+
}
227+
228+
for _, tt := range tests {
229+
tt := tt
230+
t.Run(tt.name, func(t *testing.T) {
231+
t.Parallel()
232+
mx, err := GetData(tt.inidata, tt.ctx, tt.compiler)
233+
if (err != nil) != tt.wantErr {
234+
t.Fatalf("GetData() error=%v wantErr=%v", err, tt.wantErr)
235+
}
236+
if tt.wantErr {
237+
return
238+
}
239+
tt.check(t, mx)
240+
})
241+
}
242+
}
243+
244+
// containsAll checks whether all expected values are present in the slice
245+
func containsAll(have []string, expected []string) bool {
246+
set := make(map[string]struct{}, len(have))
247+
for _, v := range have {
248+
set[v] = struct{}{}
249+
}
250+
for _, e := range expected {
251+
if _, ok := set[e]; !ok {
252+
return false
253+
}
254+
}
255+
return true
256+
}

0 commit comments

Comments
 (0)