From 3eeda8fd79a1873232db78175700c9e8a2aef9f2 Mon Sep 17 00:00:00 2001 From: Jean-Marc MEESSEN Date: Sun, 9 Aug 2020 16:15:40 +0200 Subject: [PATCH] Improve tests coverage --- flecmd/csv.go | 12 +- flecmd/load.go | 6 +- fleprocess/CSV_process.go | 50 ---- fleprocess/adif_process.go | 2 +- fleprocess/adif_write.go | 32 --- fleprocess/adif_write_test.go | 16 ++ fleprocess/braketedData_test.go | 16 ++ fleprocess/csv_process.go | 103 ++++++++ fleprocess/csv_process_test.go | 80 +++++++ fleprocess/csv_write.go | 2 - fleprocess/csv_write_test.go | 16 ++ fleprocess/displayLog.go | 4 +- fleprocess/displayLog_test.go | 185 ++++++++++++++ fleprocess/inferTime_test.go | 16 ++ fleprocess/load_file.go | 31 +-- fleprocess/load_file_test.go | 373 +++++++++++++++++++++++++++++ fleprocess/output_filename_test.go | 16 ++ fleprocess/parse_line_test.go | 21 ++ fleprocess/validate_test.go | 16 ++ fleprocess/write_file.go | 53 ++++ fleprocess/write_file_test.go | 67 ++++++ test/data/fle-3-error.txt | 11 + test/data/fle-4-no-qso.txt | 7 + 23 files changed, 1024 insertions(+), 111 deletions(-) delete mode 100644 fleprocess/CSV_process.go create mode 100644 fleprocess/csv_process.go create mode 100644 fleprocess/csv_process_test.go create mode 100644 fleprocess/displayLog_test.go create mode 100644 fleprocess/load_file_test.go create mode 100644 fleprocess/write_file.go create mode 100644 fleprocess/write_file_test.go create mode 100644 test/data/fle-3-error.txt create mode 100644 test/data/fle-4-no-qso.txt diff --git a/flecmd/csv.go b/flecmd/csv.go index 22f62ae..d2d3367 100644 --- a/flecmd/csv.go +++ b/flecmd/csv.go @@ -19,6 +19,7 @@ limitations under the License. import ( "FLEcli/fleprocess" "fmt" + "os" "github.com/spf13/cobra" ) @@ -34,7 +35,7 @@ var csvCmd = &cobra.Command{ // and usage of using your command. For example: RunE: func(cmd *cobra.Command, args []string) error { - //if args is empty, throw an error + //if args is empty, throw an error (Cobra will display the ) if len(args) == 0 { //TODO: fix this ugly statement (because I am lazy) return fmt.Errorf("Missing input file %s", "") @@ -47,9 +48,11 @@ var csvCmd = &cobra.Command{ return fmt.Errorf("Too many arguments.%s", "") } - - //TODO: should return an error - fleprocess.ProcessCsvCommand(inputFilename, outputCsvFilename, isInterpolateTime, isOverwriteCsv) + if err := fleprocess.ProcessCsvCommand(inputFilename, outputCsvFilename, isInterpolateTime, isOverwriteCsv); err != nil { + fmt.Println("\nUnable to generate CSV file:") + fmt.Println(err) + os.Exit(1) + } return nil }, } @@ -61,4 +64,3 @@ func init() { csvCmd.PersistentFlags().BoolVarP(&isOverwriteCsv, "overwrite", "o", false, "Overwrites the output file if it exisits") } - diff --git a/flecmd/load.go b/flecmd/load.go index 94ce1d6..e2e6023 100644 --- a/flecmd/load.go +++ b/flecmd/load.go @@ -37,10 +37,10 @@ var loadCmd = &cobra.Command{ //if args is empty, throw an error if len(args) == 0 { //TODO: fix this ugly statement (because I am lazy) - return fmt.Errorf("Missing input file %s","") + return fmt.Errorf("Missing input file %s", "") } if len(args) > 1 { - return fmt.Errorf("Too many arguments.%s","") + return fmt.Errorf("Too many arguments.%s", "") } inputFilename = args[0] fleprocess.LoadFile(inputFilename, isInterpolateTime) @@ -53,5 +53,3 @@ func init() { loadCmd.PersistentFlags().BoolVarP(&isInterpolateTime, "interpolate", "i", false, "Interpolates the missing time entries.") } - - diff --git a/fleprocess/CSV_process.go b/fleprocess/CSV_process.go deleted file mode 100644 index 72c2432..0000000 --- a/fleprocess/CSV_process.go +++ /dev/null @@ -1,50 +0,0 @@ -package fleprocess - -/* -Copyright © 2020 Jean-Marc Meessen, ON4KJM - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -//Documentation of SOTA CSV format: https://www.sotadata.org.uk/en/upload/activator/csv/info - -import ( - "fmt" -) - -//ProcessCsvCommand loads an FLE input to produce a SOTA CSV -func ProcessCsvCommand(inputFilename, outputCsvFilename string, isInterpolateTime, isOverwriteCsv bool) { - - verifiedOutputFilename, filenameWasOK := buildOutputFilename(outputCsvFilename, inputFilename, isOverwriteCsv, ".csv") - - // if the output file could not be parsed correctly do noting - if filenameWasOK { - loadedLogFile, isLoadedOK := LoadFile(inputFilename, isInterpolateTime) - - //TODO: move this in a function so that it can be more easily tested - if isLoadedOK { - if len(loadedLogFile) == 0 { - fmt.Println("No useful data read. Aborting...") - return - } - - //check if we have the necessary information for the type - if loadedLogFile[0].MySOTA == "" { - fmt.Println("Missing MY-SOTA reference. Aborting...") - return - } - - outputCsv(verifiedOutputFilename, loadedLogFile) - } - } -} diff --git a/fleprocess/adif_process.go b/fleprocess/adif_process.go index 2b3f41b..5901171 100644 --- a/fleprocess/adif_process.go +++ b/fleprocess/adif_process.go @@ -27,7 +27,7 @@ func ProcessAdifCommand(inputFilename, outputFilename string, isInterpolateTime, // if the output file could not be parsed correctly do noting if filenameWasOK { - loadedLogFile, isLoadedOK := LoadFile(inputFilename,isInterpolateTime) + loadedLogFile, isLoadedOK := LoadFile(inputFilename, isInterpolateTime) if isLoadedOK { if len(loadedLogFile) == 0 { diff --git a/fleprocess/adif_write.go b/fleprocess/adif_write.go index 9d4d2e4..c7bb694 100644 --- a/fleprocess/adif_write.go +++ b/fleprocess/adif_write.go @@ -17,9 +17,7 @@ limitations under the License. */ import ( - "bufio" "fmt" - "os" "strings" "time" ) @@ -87,41 +85,11 @@ func buildAdif(fullLog []LogLine, isWWFF bool, isSOTA bool) (adifList []string) return adifList } -// writeFile writes the in-memory data (lines) to a file -func writeFile(outputFile string, adifData []string) { - - //TODO: check access rights - f, err := os.Create(outputFile) - checkFileError(err) - - defer f.Close() - - w := bufio.NewWriter(f) - - lineCount := 0 - for _, adifLine := range adifData { - _, err := w.WriteString(adifLine + "\n") - checkFileError(err) - - w.Flush() - checkFileError(err) - lineCount++ - } - fmt.Printf("\nSuccessfully wrote %d lines to file \"%s\"\n", lineCount, outputFile) -} - // adifElement generated the ADIF sub-element func adifElement(elementName, elementValue string) (element string) { return fmt.Sprintf("<%s:%d>%s ", strings.ToUpper(elementName), len(elementValue), elementValue) } -// checkFileError handles file related errors -func checkFileError(e error) { - if e != nil { - panic(e) - } -} - //adifDate converts a date in YYYY-MM-DD format to YYYYMMDD func adifDate(inputDate string) (outputDate string) { const FLEdateFormat = "2006-01-02" diff --git a/fleprocess/adif_write_test.go b/fleprocess/adif_write_test.go index 987b797..81f9714 100644 --- a/fleprocess/adif_write_test.go +++ b/fleprocess/adif_write_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "reflect" "testing" diff --git a/fleprocess/braketedData_test.go b/fleprocess/braketedData_test.go index 7597e18..a6d3afa 100644 --- a/fleprocess/braketedData_test.go +++ b/fleprocess/braketedData_test.go @@ -2,6 +2,22 @@ package fleprocess import "testing" +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + func Test_getBraketedData(t *testing.T) { type args struct { inputLine string diff --git a/fleprocess/csv_process.go b/fleprocess/csv_process.go new file mode 100644 index 0000000..86ad1f1 --- /dev/null +++ b/fleprocess/csv_process.go @@ -0,0 +1,103 @@ +package fleprocess + +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//Documentation of the SOTA CSV format: https://www.sotadata.org.uk/en/upload/activator/csv/info + +import ( + "fmt" + "strings" +) + +//ProcessCsvCommand loads an FLE input to produce a SOTA CSV +func ProcessCsvCommand(inputFilename, outputCsvFilename string, isInterpolateTime, isOverwriteCsv bool) error { + + if verifiedOutputFilename, filenameWasOK := buildOutputFilename(outputCsvFilename, inputFilename, isOverwriteCsv, ".csv"); filenameWasOK == true { + if loadedLogFile, isLoadedOK := LoadFile(inputFilename, isInterpolateTime); isLoadedOK == true { + if err := validateDataForSotaCsv(loadedLogFile); err != nil { + return err + } + outputCsv(verifiedOutputFilename, loadedLogFile) + return nil + } + return fmt.Errorf("There were input file parsing errors. Could not generate CSV file") + } + //TODO: we need something more explicit here + return fmt.Errorf("Failed to compute or validate output file name") +} + +func validateDataForSotaCsv(loadedLogFile []LogLine) error { + if len(loadedLogFile) == 0 { + return fmt.Errorf("No QSO found") + } + + //MySOTA and MyCall are header values. If missing on the first line, it will be missing at every line + if loadedLogFile[0].MySOTA == "" { + return fmt.Errorf("Missing MY-SOTA reference") + } + if loadedLogFile[0].MyCall == "" { + return fmt.Errorf("Missing MyCall") + } + + var errorsBuffer strings.Builder + //We accumulate the errors messages + for i := 0; i < len(loadedLogFile); i++ { + + //Compute the error location for a meaning full error + var errorLocation string + if loadedLogFile[i].Time == "" { + errorLocation = fmt.Sprintf("for log entry #%d", i+1) + } else { + errorLocation = fmt.Sprintf("for log entry at %s (#%d)", loadedLogFile[i].Time, i+1) + } + + if loadedLogFile[i].Date == "" { + if errorsBuffer.String() != "" { + errorsBuffer.WriteString(fmt.Sprintf(", ")) + } + errorsBuffer.WriteString(fmt.Sprintf("missing date %s", errorLocation)) + } + if loadedLogFile[i].Band == "" { + if errorsBuffer.String() != "" { + errorsBuffer.WriteString(fmt.Sprintf(", ")) + } + errorsBuffer.WriteString(fmt.Sprintf("missing band %s", errorLocation)) + } + if loadedLogFile[i].Mode == "" { + if errorsBuffer.String() != "" { + errorsBuffer.WriteString(fmt.Sprintf(", ")) + } + errorsBuffer.WriteString(fmt.Sprintf("missing mode %s", errorLocation)) + } + if loadedLogFile[i].Call == "" { + if errorsBuffer.String() != "" { + errorsBuffer.WriteString(fmt.Sprintf(", ")) + } + errorsBuffer.WriteString(fmt.Sprintf("missing call %s", errorLocation)) + } + if loadedLogFile[i].Time == "" { + if errorsBuffer.String() != "" { + errorsBuffer.WriteString(fmt.Sprintf(", ")) + } + errorsBuffer.WriteString(fmt.Sprintf("missing QSO time %s", errorLocation)) + } + } + if errorsBuffer.String() != "" { + return fmt.Errorf(errorsBuffer.String()) + } + return nil +} diff --git a/fleprocess/csv_process_test.go b/fleprocess/csv_process_test.go new file mode 100644 index 0000000..48715d9 --- /dev/null +++ b/fleprocess/csv_process_test.go @@ -0,0 +1,80 @@ +package fleprocess + +import ( + "fmt" + "testing" +) + +func Test_validateDataForSotaCsv(t *testing.T) { + type args struct { + loadedLogFile []LogLine + } + tests := []struct { + name string + args args + want error + }{ + { + "Happy Case", + args{loadedLogFile: []LogLine{ + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "time", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "time", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "time", Call: "call"}}, + }, + nil, + }, + { + "Missing Date", + args{loadedLogFile: []LogLine{ + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:01", Call: "call"}, + {Date: "", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:02", Call: "call"}, + {Date: "", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:03", Call: "call"}}, + }, + fmt.Errorf("missing date for log entry at 12:02 (#2), missing date for log entry at 12:03 (#3)"), + }, + { + "Missing MyCall", + args{loadedLogFile: []LogLine{ + {Date: "date", MyCall: "", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:01", Call: "call"}, + {Date: "date", MyCall: "", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:02", Call: "call"}, + {Date: "date", MyCall: "", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:03", Call: "call"}}, + }, + fmt.Errorf("Missing MyCall"), + }, + { + "Missing MySota", + args{loadedLogFile: []LogLine{ + {Date: "date", MyCall: "myCall", MySOTA: "", Mode: "mode", Band: "band", Time: "time", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "", Mode: "mode", Band: "band", Time: "time", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "", Mode: "mode", Band: "band", Time: "time", Call: "call"}}, + }, + fmt.Errorf("Missing MY-SOTA reference"), + }, + { + "Misc. missing data (Band, Time, Mode, Call)", + args{loadedLogFile: []LogLine{ + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "", Time: "", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "", Band: "band", Time: "12:02", Call: "call"}, + {Date: "date", MyCall: "myCall", MySOTA: "mySota", Mode: "mode", Band: "band", Time: "12:03", Call: ""}}, + }, + fmt.Errorf("missing band for log entry #1, missing QSO time for log entry #1, missing mode for log entry at 12:02 (#2), missing call for log entry at 12:03 (#3)"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := validateDataForSotaCsv(tt.args.loadedLogFile) + if tt.want == nil || got == nil { + if tt.want == nil && got != nil { + t.Errorf("validateDataForSotaCsv() = %v, want %v", got, nil) + } + if tt.want != nil && got == nil { + t.Errorf("validateDataForSotaCsv() = %v, want %v", nil, tt.want) + } + } else { + if got.Error() != tt.want.Error() { + t.Errorf("validateDataForSotaCsv() = %v, want %v", got, tt.want) + } + } + }) + } +} diff --git a/fleprocess/csv_write.go b/fleprocess/csv_write.go index b595ed6..2cf69d7 100644 --- a/fleprocess/csv_write.go +++ b/fleprocess/csv_write.go @@ -25,8 +25,6 @@ import ( // outputAdif generates and writes data in ADIF format func outputCsv(outputFile string, fullLog []LogLine) { - //TODO: validate input data for combination - //convert the log data to an in-memory ADIF file csvData := buildCsv(fullLog) diff --git a/fleprocess/csv_write_test.go b/fleprocess/csv_write_test.go index 6fccebc..e3e944f 100644 --- a/fleprocess/csv_write_test.go +++ b/fleprocess/csv_write_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "reflect" "testing" diff --git a/fleprocess/displayLog.go b/fleprocess/displayLog.go index 336038b..8c13276 100644 --- a/fleprocess/displayLog.go +++ b/fleprocess/displayLog.go @@ -73,10 +73,10 @@ func SprintHeaderValues(logLine LogLine) string { } // Date, Time, band, mode, call, report sent, report rcvd, Notes -var logLineFormat = "%-10s %-4s %-4s %-4s %-10s %-4s %-4s %s \n" +var logLineFormat = "%-10s %-4s %-4s %-4s %-10s %-4s %-4s %s\n" // SprintColumnTitles displays the column titles for a log line -func SprintColumnTitles(logLine LogLine) string { +func SprintColumnTitles() string { var output strings.Builder output.WriteString(fmt.Sprintf(logLineFormat, "Date", "Time", "Band", "Mode", "Call", "Sent", "Rcvd", "Notes")) output.WriteString(fmt.Sprintf(logLineFormat, "----", "----", "----", "----", "----", "----", "----", "----")) diff --git a/fleprocess/displayLog_test.go b/fleprocess/displayLog_test.go new file mode 100644 index 0000000..d9329a5 --- /dev/null +++ b/fleprocess/displayLog_test.go @@ -0,0 +1,185 @@ +package fleprocess + +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + "testing" +) + +func TestSprintHeaderValues(t *testing.T) { + type args struct { + logLine LogLine + } + tests := []struct { + name string + args args + want string + }{ + { + "Full Option", + args{logLine: LogLine{MyCall: "on4kjm/p", Operator: "on4kjm", MyWWFF: "wwff", MySOTA: "sota"}}, + "MyCall on4kjm/p (on4kjm)\nMyWWFF wwff\nMySOTA sota\n", + }, + { + "Minimal", + args{logLine: LogLine{MyCall: "on4kjm/p"}}, + "MyCall on4kjm/p\n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SprintHeaderValues(tt.args.logLine); got != tt.want { + t.Errorf("SprintHeaderValues() = %v, want %v", got, tt.want) + } + }) + } +} + +func ExampleSprintColumnTitles() { + out := SprintColumnTitles() + fmt.Print(out) + //Output: + //Date Time Band Mode Call Sent Rcvd Notes + //---- ---- ---- ---- ---- ---- ---- ---- +} + +func ExampleSprintLogRecord() { + logLine := LogLine{ + Date: "date", + MyCall: "myCall", + Operator: "operator", + MyWWFF: "myWwff", + MySOTA: "mySota", + QslMsgFromHeader: "QslMsgFromHeader", + Nickname: "nickname", + Mode: "mode", + ModeType: "modeType", + Band: "band", + BandLowerLimit: 1.0, + BandUpperLimit: 2.0, + Frequency: "frequency", + Time: "time", + Call: "call", + Comment: "comment", + QSLmsg: "qslMessage", + OMname: "omName", + GridLoc: "gridLoc", + RSTsent: "rstSent", + RSTrcvd: "rstRcvd", + SOTA: "sota", + WWFF: "wwff", + } + out := SprintLogRecord(logLine) + fmt.Print(out) + + //output: + //Date date + //MyCall myCall + //Operator operator + //MyWWFF myWwff + //MySOTA mySota + //QslMsg QslMsgFromHeader + //Nickname nickname + //Mode mode + //ModeType modeType + //Band band + // Lower 1.000000 + // Upper 2.000000 + //Frequency frequency + //Time time + //Call call + //Comment comment + //QSLmsg qslMessage + //OMname omName + //GridLoc gridLoc + //RSTsent rstSent + //RSTrcvd rstRcvd + //SOTA sota + //WWFF wwff + +} + +func TestSprintLogInColumn(t *testing.T) { + type args struct { + logLine LogLine + } + tests := []struct { + name string + args args + wantOutput string + }{ + { + "Full Option", + args{logLine: LogLine{ + Date: "date", + MyCall: "myCall", + Operator: "operator", + MyWWFF: "myWwff", + MySOTA: "mySota", + QslMsgFromHeader: "QslMsgFromHeader", + Nickname: "nickname", + Mode: "mode", + ModeType: "modeType", + Band: "band", + BandLowerLimit: 1.0, + BandUpperLimit: 2.0, + Frequency: "frequency", + Time: "time", + Call: "call", + Comment: "comment", + QSLmsg: "qslMessage", + OMname: "omName", + GridLoc: "gridLoc", + RSTsent: "rstSent", + RSTrcvd: "rstRcvd", + SOTA: "sota", + WWFF: "wwff"}, + }, + "date time band mode call rstSent rstRcvd QRG: frequency [comment] [qslMessage] omName gridLoc wwff sota \n", + }, + { + "Minimal", + args{logLine: LogLine{ + Date: "date", + MyCall: "myCall", + Operator: "operator", + MyWWFF: "myWwff", + MySOTA: "mySota", + QslMsgFromHeader: "QslMsgFromHeader", + Nickname: "nickname", + Mode: "mode", + ModeType: "modeType", + Band: "band", + BandLowerLimit: 1.0, + BandUpperLimit: 2.0, + Time: "time", + Call: "call", + RSTsent: "rstSent", + RSTrcvd: "rstRcvd"}, + }, + "date time band mode call rstSent rstRcvd \n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotOutput := SprintLogInColumn(tt.args.logLine); gotOutput != tt.wantOutput { + t.Errorf("SprintLogInColumn() = %v, want %v", gotOutput, tt.wantOutput) + } + }) + } +} diff --git a/fleprocess/inferTime_test.go b/fleprocess/inferTime_test.go index ca5cb2d..de4a402 100644 --- a/fleprocess/inferTime_test.go +++ b/fleprocess/inferTime_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "fmt" "testing" diff --git a/fleprocess/load_file.go b/fleprocess/load_file.go index b0c603c..317e97f 100644 --- a/fleprocess/load_file.go +++ b/fleprocess/load_file.go @@ -22,6 +22,7 @@ import ( "log" "os" "regexp" + "strings" "time" ) @@ -48,10 +49,10 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL file.Close() - regexpLineComment, _ := regexp.Compile("^#") + regexpLineComment, _ := regexp.Compile("^[[:blank:]]*#") regexpOnlySpaces, _ := regexp.Compile("^\\s+$") - regexpSingleMultiLineComment, _ := regexp.Compile("^{.+}$") - regexpStartMultiLineComment, _ := regexp.Compile("^{") + regexpSingleMultiLineComment, _ := regexp.Compile("^[[:blank:]]*{.+}$") + regexpStartMultiLineComment, _ := regexp.Compile("^[[:blank:]]*{") regexpEndMultiLineComment, _ := regexp.Compile("}$") regexpHeaderMyCall, _ := regexp.Compile("(?i)^mycall ") regexpHeaderOperator, _ := regexp.Compile("(?i)^operator ") @@ -121,8 +122,8 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL if regexpHeaderMyCall.MatchString(eachline) { errorMsg := "" myCallList := regexpHeaderMyCall.Split(eachline, -1) - if len(myCallList[1]) > 0 { - headerMyCall, errorMsg = ValidateCall(myCallList[1]) + if len(strings.TrimSpace(myCallList[1])) > 0 { + headerMyCall, errorMsg = ValidateCall(strings.TrimSpace(myCallList[1])) cleanedInput = append(cleanedInput, fmt.Sprintf("My call: %s", headerMyCall)) if len(errorMsg) != 0 { errorLog = append(errorLog, fmt.Sprintf("Invalid myCall at line %d: %s (%s)", lineCount, myCallList[1], errorMsg)) @@ -136,8 +137,8 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL if regexpHeaderOperator.MatchString(eachline) { errorMsg := "" myOperatorList := regexpHeaderOperator.Split(eachline, -1) - if len(myOperatorList[1]) > 0 { - headerOperator, errorMsg = ValidateCall(myOperatorList[1]) + if len(strings.TrimSpace(myOperatorList[1])) > 0 { + headerOperator, errorMsg = ValidateCall(strings.TrimSpace(myOperatorList[1])) cleanedInput = append(cleanedInput, fmt.Sprintf("Operator: %s", headerOperator)) if len(errorMsg) != 0 { errorLog = append(errorLog, fmt.Sprintf("Invalid Operator at line %d: %s (%s)", lineCount, myOperatorList[1], errorMsg)) @@ -151,8 +152,8 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL if regexpHeaderMyWwff.MatchString(eachline) { errorMsg := "" myWwffList := regexpHeaderMyWwff.Split(eachline, -1) - if len(myWwffList[1]) > 0 { - headerMyWWFF, errorMsg = ValidateWwff(myWwffList[1]) + if len(strings.TrimSpace(myWwffList[1])) > 0 { + headerMyWWFF, errorMsg = ValidateWwff(strings.TrimSpace(myWwffList[1])) cleanedInput = append(cleanedInput, fmt.Sprintf("My WWFF: %s", headerMyWWFF)) if len(errorMsg) != 0 { errorLog = append(errorLog, fmt.Sprintf("Invalid \"My WWFF\" at line %d: %s (%s)", lineCount, myWwffList[1], errorMsg)) @@ -166,8 +167,8 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL if regexpHeaderMySota.MatchString(eachline) { errorMsg := "" mySotaList := regexpHeaderMySota.Split(eachline, -1) - if len(mySotaList[1]) > 0 { - headerMySOTA, errorMsg = ValidateSota(mySotaList[1]) + if len(strings.TrimSpace(mySotaList[1])) > 0 { + headerMySOTA, errorMsg = ValidateSota(strings.TrimSpace(mySotaList[1])) cleanedInput = append(cleanedInput, fmt.Sprintf("My Sota: %s", headerMySOTA)) if len(errorMsg) != 0 { errorLog = append(errorLog, fmt.Sprintf("Invalid \"My SOTA\" at line %d: %s (%s)", lineCount, mySotaList[1], errorMsg)) @@ -191,8 +192,8 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL //Nickname if regexpHeaderNickname.MatchString(eachline) { myNicknameList := regexpHeaderNickname.Split(eachline, -1) - if len(myNicknameList[1]) > 0 { - headerNickname = myNicknameList[1] + if len(strings.TrimSpace(myNicknameList[1])) > 0 { + headerNickname = strings.TrimSpace(myNicknameList[1]) cleanedInput = append(cleanedInput, fmt.Sprintf("eQSL Nickmane: %s", headerNickname)) } //If there is no data after the marker, we just skip the data. @@ -316,10 +317,10 @@ func displayLogSimple(fullLog []LogLine) { for _, filledLogLine := range fullLog { if firstLine { fmt.Println(SprintHeaderValues(filledLogLine)) - fmt.Print(SprintColumnTitles(filledLogLine)) + fmt.Print(SprintColumnTitles()) firstLine = false } fmt.Print(SprintLogInColumn(filledLogLine)) } -} \ No newline at end of file +} diff --git a/fleprocess/load_file_test.go b/fleprocess/load_file_test.go new file mode 100644 index 0000000..49c4a55 --- /dev/null +++ b/fleprocess/load_file_test.go @@ -0,0 +1,373 @@ +package fleprocess + +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "fmt" + "io/ioutil" + "os" + "testing" +) + +func TestLoadFile_happyCase(t *testing.T) { + + //Given + dataArray := make([]string, 0) + dataArray = append(dataArray, "{ Sample multi-line comment") + dataArray = append(dataArray, " ( with quotes) Check: Logging > \"Contest Logging\"") + dataArray = append(dataArray, " - Data item1") + dataArray = append(dataArray, " - Data item2") + dataArray = append(dataArray, " }") + dataArray = append(dataArray, "{ one liner comment }") + dataArray = append(dataArray, " { offset one liner comment }") + dataArray = append(dataArray, " ") + dataArray = append(dataArray, "# Header") + dataArray = append(dataArray, "myCall on4kjm/p") + dataArray = append(dataArray, "operator on4kjm") + dataArray = append(dataArray, "nickname Portable") + dataArray = append(dataArray, "myWwff onff-0258") + dataArray = append(dataArray, "mySota on/on-001") + dataArray = append(dataArray, "QslMsg This is a QSL message") + dataArray = append(dataArray, " ") + dataArray = append(dataArray, " #Log") + dataArray = append(dataArray, "date 2020-05-23") + dataArray = append(dataArray, "40m cw 0950 ik5zve/5 9 5") + dataArray = append(dataArray, "on6zq") + dataArray = append(dataArray, "0954 on4do") + + temporaryDataFileName := createTestFile(dataArray) + + //When + loadedLogFile, isLoadedOK := LoadFile(temporaryDataFileName, true) + + //Then + if !isLoadedOK { + t.Error("Test file could not be correctly processed") + } + if len(loadedLogFile) == 0 { + t.Error("No data loaded") + } + + expectedValue := "ON4KJM/P" + if loadedLogFile[0].MyCall != expectedValue { + t.Errorf("Not the expected MyCall value: %s (expecting %s)", loadedLogFile[0].MyCall, expectedValue) + } + expectedValue = "ON4KJM" + if loadedLogFile[0].Operator != expectedValue { + t.Errorf("Not the expected Operator value: %s (expecting %s)", loadedLogFile[0].Operator, expectedValue) + } + expectedValue = "Portable" + if loadedLogFile[0].Nickname != expectedValue { + t.Errorf("Not the expected eQsl Nickname value: %s (expecting %s)", loadedLogFile[0].Nickname, expectedValue) + } + expectedValue = "ONFF-0258" + if loadedLogFile[0].MyWWFF != expectedValue { + t.Errorf("Not the expected MyWWFF value: %s (expecting %s)", loadedLogFile[0].MyWWFF, expectedValue) + } + expectedValue = "ON/ON-001" + if loadedLogFile[0].MySOTA != expectedValue { + t.Errorf("Not the expected MySOTA value: %s (expecting %s)", loadedLogFile[0].MySOTA, expectedValue) + } + expectedValue = "This is a QSL message" + if loadedLogFile[0].QSLmsg != expectedValue { + t.Errorf("Not the expected QSL Message from Header value: %s (expecting %s)", loadedLogFile[0].QSLmsg, expectedValue) + } + expectedValue = "IK5ZVE/5" + if loadedLogFile[0].Call != expectedValue { + t.Errorf("Not the expected Call[0] value: %s (expecting %s)", loadedLogFile[0].Call, expectedValue) + } + expectedValue = "0950" + if loadedLogFile[0].Time != expectedValue { + t.Errorf("Not the expected Time[0] value: %s (expecting %s)", loadedLogFile[0].Time, expectedValue) + } + expectedValue = "2020-05-23" + if loadedLogFile[0].Date != expectedValue { + t.Errorf("Not the expected Date[0] value: %s (expecting %s)", loadedLogFile[0].Date, expectedValue) + } + expectedValue = "ON6ZQ" + if loadedLogFile[1].Call != expectedValue { + t.Errorf("Not the expected Call[1] value: %s (expecting %s)", loadedLogFile[1].Call, expectedValue) + } + expectedValue = "0952" + if loadedLogFile[1].Time != expectedValue { + t.Errorf("Not the expected Time[1] value: %s (expecting %s)", loadedLogFile[1].Time, expectedValue) + } + expectedValue = "ON4DO" + if loadedLogFile[2].Call != expectedValue { + t.Errorf("Not the expected Call[2] value: %s (expecting %s)", loadedLogFile[2].Call, expectedValue) + } + expectedValue = "0954" + if loadedLogFile[2].Time != expectedValue { + t.Errorf("Not the expected Time[2] value: %s (expecting %s)", loadedLogFile[2].Time, expectedValue) + } + //Clean Up + os.Remove(temporaryDataFileName) +} + +func TestLoadFile_wrongHeader(t *testing.T) { + + //Given + dataArray := make([]string, 0) + dataArray = append(dataArray, "# Header") + dataArray = append(dataArray, "myCall fooBar") + dataArray = append(dataArray, "operator") + dataArray = append(dataArray, "myWwff foobar") + dataArray = append(dataArray, "mySota ") + dataArray = append(dataArray, " ") + dataArray = append(dataArray, " #Log") + dataArray = append(dataArray, "date 2020-05-23") + dataArray = append(dataArray, "40m cw 0950 ik5zve/5 9 5") + dataArray = append(dataArray, "on6zq") + dataArray = append(dataArray, "0954 on4do") + + temporaryDataFileName := createTestFile(dataArray) + + //When + loadedLogFile, isLoadedOK := LoadFile(temporaryDataFileName, true) + + //Then + if isLoadedOK { + t.Error("Test file processing should return with aerror") + } + if len(loadedLogFile) == 0 { + t.Error("No data loaded") + } + + expectedValue := "*FOOBAR" + if loadedLogFile[0].MyCall != expectedValue { + t.Errorf("Not the expected MyCall value: %s (expecting %s)", loadedLogFile[0].MyCall, expectedValue) + } + expectedValue = "" + if loadedLogFile[0].Operator != expectedValue { + t.Errorf("Not the expected Operator value: %s (expecting %s)", loadedLogFile[0].Operator, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].MyWWFF != expectedValue { + t.Errorf("Not the expected MyWWFF value: %s (expecting %s)", loadedLogFile[0].MyWWFF, expectedValue) + } + expectedValue = "" + if loadedLogFile[0].MySOTA != expectedValue { + t.Errorf("Not the expected MySOTA value: %s (expecting %s)", loadedLogFile[0].MySOTA, expectedValue) + } + + expectedValue = "IK5ZVE/5" + if loadedLogFile[0].Call != expectedValue { + t.Errorf("Not the expected Call[0] value: %s (expecting %s)", loadedLogFile[0].Call, expectedValue) + } + expectedValue = "0950" + if loadedLogFile[0].Time != expectedValue { + t.Errorf("Not the expected Time[0] value: %s (expecting %s)", loadedLogFile[0].Time, expectedValue) + } + expectedValue = "2020-05-23" + if loadedLogFile[0].Date != expectedValue { + t.Errorf("Not the expected Date[0] value: %s (expecting %s)", loadedLogFile[0].Date, expectedValue) + } + expectedValue = "ON6ZQ" + if loadedLogFile[1].Call != expectedValue { + t.Errorf("Not the expected Call[1] value: %s (expecting %s)", loadedLogFile[1].Call, expectedValue) + } + expectedValue = "0952" + if loadedLogFile[1].Time != expectedValue { + t.Errorf("Not the expected Time[1] value: %s (expecting %s)", loadedLogFile[1].Time, expectedValue) + } + expectedValue = "ON4DO" + if loadedLogFile[2].Call != expectedValue { + t.Errorf("Not the expected Call[2] value: %s (expecting %s)", loadedLogFile[2].Call, expectedValue) + } + expectedValue = "0954" + if loadedLogFile[2].Time != expectedValue { + t.Errorf("Not the expected Time[2] value: %s (expecting %s)", loadedLogFile[2].Time, expectedValue) + } + //Clean Up + os.Remove(temporaryDataFileName) +} + +//TODO: if the first call is wrong the infertime doesn't work + +func TestLoadFile_wrongData(t *testing.T) { + + //Given + dataArray := make([]string, 0) + dataArray = append(dataArray, "# Header") + dataArray = append(dataArray, "myCall fooBar") + dataArray = append(dataArray, "operator foobar") + dataArray = append(dataArray, "myWwff foobar") + dataArray = append(dataArray, "mySota foobar") + dataArray = append(dataArray, " ") + dataArray = append(dataArray, " #Log") + dataArray = append(dataArray, "date 2020-05-23") + dataArray = append(dataArray, "40m cw 0950 ik5zve 9 5") + dataArray = append(dataArray, "on6zq") + dataArray = append(dataArray, "42m 0954 on4do") + + temporaryDataFileName := createTestFile(dataArray) + + //When + loadedLogFile, isLoadedOK := LoadFile(temporaryDataFileName, true) + + //Then + if isLoadedOK { + t.Error("Test file processing should return with an error") + } + if len(loadedLogFile) == 0 { + t.Error("No data loaded") + } + + expectedValue := "*FOOBAR" + if loadedLogFile[0].MyCall != expectedValue { + t.Errorf("Not the expected MyCall value: %s (expecting %s)", loadedLogFile[0].MyCall, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].Operator != expectedValue { + t.Errorf("Not the expected Operator value: %s (expecting %s)", loadedLogFile[0].Operator, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].MyWWFF != expectedValue { + t.Errorf("Not the expected MyWWFF value: %s (expecting %s)", loadedLogFile[0].MyWWFF, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].MySOTA != expectedValue { + t.Errorf("Not the expected MySOTA value: %s (expecting %s)", loadedLogFile[0].MySOTA, expectedValue) + } + + expectedValue = "IK5ZVE" + if loadedLogFile[0].Call != expectedValue { + t.Errorf("Not the expected Call[0] value: %s (expecting %s)", loadedLogFile[0].Call, expectedValue) + } + expectedValue = "0950" + if loadedLogFile[0].Time != expectedValue { + t.Errorf("Not the expected Time[0] value: %s (expecting %s)", loadedLogFile[0].Time, expectedValue) + } + expectedValue = "2020-05-23" + if loadedLogFile[0].Date != expectedValue { + t.Errorf("Not the expected Date[0] value: %s (expecting %s)", loadedLogFile[0].Date, expectedValue) + } + expectedValue = "ON6ZQ" + if loadedLogFile[1].Call != expectedValue { + t.Errorf("Not the expected Call[1] value: %s (expecting %s)", loadedLogFile[1].Call, expectedValue) + } + expectedValue = "0952" + if loadedLogFile[1].Time != expectedValue { + t.Errorf("Not the expected Time[1] value: %s (expecting %s)", loadedLogFile[1].Time, expectedValue) + } + expectedValue = "ON4DO" + if loadedLogFile[2].Call != expectedValue { + t.Errorf("Not the expected Call[2] value: %s (expecting %s)", loadedLogFile[2].Call, expectedValue) + } + expectedValue = "0954" + if loadedLogFile[2].Time != expectedValue { + t.Errorf("Not the expected Time[2] value: %s (expecting %s)", loadedLogFile[2].Time, expectedValue) + } + //Clean Up + os.Remove(temporaryDataFileName) +} + +func TestLoadFile_firstCallWrong(t *testing.T) { + + //Given + dataArray := make([]string, 0) + dataArray = append(dataArray, "# Header") + dataArray = append(dataArray, "myCall fooBar") + dataArray = append(dataArray, "operator foobar") + dataArray = append(dataArray, "myWwff foobar") + dataArray = append(dataArray, "mySota foobar") + dataArray = append(dataArray, " ") + dataArray = append(dataArray, " #Log") + dataArray = append(dataArray, "date 2020-05-23") + dataArray = append(dataArray, "40m cw 0950 on4kjm/p/qrp 9 5") + dataArray = append(dataArray, "on6zq") + dataArray = append(dataArray, "42m 0954 on4do") + + temporaryDataFileName := createTestFile(dataArray) + + //When + loadedLogFile, isLoadedOK := LoadFile(temporaryDataFileName, true) + + //Then + if isLoadedOK { + t.Error("Test file processing should return with an error") + } + if len(loadedLogFile) == 0 { + t.Error("No data loaded") + } + + expectedValue := "*FOOBAR" + if loadedLogFile[0].MyCall != expectedValue { + t.Errorf("Not the expected MyCall value: %s (expecting %s)", loadedLogFile[0].MyCall, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].Operator != expectedValue { + t.Errorf("Not the expected Operator value: %s (expecting %s)", loadedLogFile[0].Operator, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].MyWWFF != expectedValue { + t.Errorf("Not the expected MyWWFF value: %s (expecting %s)", loadedLogFile[0].MyWWFF, expectedValue) + } + expectedValue = "*FOOBAR" + if loadedLogFile[0].MySOTA != expectedValue { + t.Errorf("Not the expected MySOTA value: %s (expecting %s)", loadedLogFile[0].MySOTA, expectedValue) + } + + expectedValue = "*ON4KJM/P/QRP" + if loadedLogFile[0].Call != expectedValue { + t.Errorf("Not the expected Call[0] value: %s (expecting %s)", loadedLogFile[0].Call, expectedValue) + } + expectedValue = "0950" + if loadedLogFile[0].Time != expectedValue { + t.Errorf("Not the expected Time[0] value: %s (expecting %s)", loadedLogFile[0].Time, expectedValue) + } + expectedValue = "2020-05-23" + if loadedLogFile[0].Date != expectedValue { + t.Errorf("Not the expected Date[0] value: %s (expecting %s)", loadedLogFile[0].Date, expectedValue) + } + expectedValue = "ON6ZQ" + if loadedLogFile[1].Call != expectedValue { + t.Errorf("Not the expected Call[1] value: %s (expecting %s)", loadedLogFile[1].Call, expectedValue) + } + expectedValue = "0952" + if loadedLogFile[1].Time != expectedValue { + t.Errorf("Not the expected Time[1] value: %s (expecting %s)", loadedLogFile[1].Time, expectedValue) + } + expectedValue = "ON4DO" + if loadedLogFile[2].Call != expectedValue { + t.Errorf("Not the expected Call[2] value: %s (expecting %s)", loadedLogFile[2].Call, expectedValue) + } + expectedValue = "0954" + if loadedLogFile[2].Time != expectedValue { + t.Errorf("Not the expected Time[2] value: %s (expecting %s)", loadedLogFile[2].Time, expectedValue) + } + //Clean Up + os.Remove(temporaryDataFileName) +} + +//createTestFile creates and populates a test FLE input file. +//Returns the created temporary filename. +func createTestFile(dataArray []string) (tempFileName string) { + //create random file name + tmpfile, err := ioutil.TempFile("", "*.txt") + if err != nil { + panic(err) + } + + fmt.Printf("Temporary file: %s", tmpfile.Name()) + + //Write the passed data to the file + writeFile(tmpfile.Name(), dataArray) + + //Return the temporaty filename + return tmpfile.Name() +} diff --git a/fleprocess/output_filename_test.go b/fleprocess/output_filename_test.go index d6dfcb8..6c508d3 100644 --- a/fleprocess/output_filename_test.go +++ b/fleprocess/output_filename_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "os" "testing" diff --git a/fleprocess/parse_line_test.go b/fleprocess/parse_line_test.go index 1901f07..a967407 100644 --- a/fleprocess/parse_line_test.go +++ b/fleprocess/parse_line_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "reflect" "testing" @@ -76,6 +92,11 @@ func TestParseLine(t *testing.T) { args{inputStr: "14.453 on4kjm", previousLine: LogLine{Mode: "SSB", Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35}}, LogLine{Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35, Call: "ON4KJM", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "Frequency [14.453] is invalid for 20m band.", }, + { + "Parse frequency out of limit with no band defined", + args{inputStr: "14.453 on4kjm", previousLine: LogLine{Mode: "SSB"}}, + LogLine{Call: "ON4KJM", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "Unable to load frequency [14.453]: no band defined for that frequency.", + }, { "parse partial RST (sent) - CW", args{inputStr: "1230 on4kjm 5", previousLine: LogLine{Mode: "CW", ModeType: "CW"}}, diff --git a/fleprocess/validate_test.go b/fleprocess/validate_test.go index 13c4d44..10fd69f 100644 --- a/fleprocess/validate_test.go +++ b/fleprocess/validate_test.go @@ -1,5 +1,21 @@ package fleprocess +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import ( "testing" ) diff --git a/fleprocess/write_file.go b/fleprocess/write_file.go new file mode 100644 index 0000000..79adf3d --- /dev/null +++ b/fleprocess/write_file.go @@ -0,0 +1,53 @@ +package fleprocess + +import ( + "bufio" + "fmt" + "os" +) + +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// writeFile writes the in-memory data (lines) to a file +func writeFile(outputFile string, dataArray []string) { + + //TODO: check access rights + f, err := os.Create(outputFile) + checkFileError(err) + + defer f.Close() + + w := bufio.NewWriter(f) + + lineCount := 0 + for _, dataLine := range dataArray { + _, err := w.WriteString(dataLine + "\n") + checkFileError(err) + + w.Flush() + checkFileError(err) + lineCount++ + } + fmt.Printf("\nSuccessfully wrote %d lines to file \"%s\"\n", lineCount, outputFile) +} + +// checkFileError handles file related errors +func checkFileError(e error) { + if e != nil { + panic(e) + } +} diff --git a/fleprocess/write_file_test.go b/fleprocess/write_file_test.go new file mode 100644 index 0000000..f45f1de --- /dev/null +++ b/fleprocess/write_file_test.go @@ -0,0 +1,67 @@ +package fleprocess + +/* +Copyright © 2020 Jean-Marc Meessen, ON4KJM + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import ( + "bufio" + "os" + "testing" +) + +const writeFileTestDir string = "test2_dir" +const writeFileTestFname string = "testFile.txt" + +func Test_writeFile(t *testing.T) { + + dataArray := make([]string, 0) + dataArray = append(dataArray, "foo") + dataArray = append(dataArray, "bar") + + writeFile(writeFileTestFname, dataArray) + + //Open and read the file we have just created + file, err := os.Open(writeFileTestFname) + + if err != nil { + t.Error(err) + } + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + var readLines []string + for scanner.Scan() { + readLines = append(readLines, scanner.Text()) + } + if error := scanner.Err(); error != nil { + t.Error(error) + } + file.Close() + + //Compare with what we have got + if len(dataArray) != len(readLines) { + t.Error("The number of lines read doesn't match the lines written") + } + for i, v := range readLines { + if v != dataArray[i] { + t.Error("Didn't read the expected data") + } + } + + // //detete test file + os.Remove(writeFileTestFname) + +} diff --git a/test/data/fle-3-error.txt b/test/data/fle-3-error.txt new file mode 100644 index 0000000..10aca7b --- /dev/null +++ b/test/data/fle-3-error.txt @@ -0,0 +1,11 @@ +date 2020-07-19 +mycall ON6ZQ/P +mysota ON/ON-018 + +#mode is missing +30m +1150 + +55 ix1ihr +cw f8dgf +56 ea2dt \ No newline at end of file diff --git a/test/data/fle-4-no-qso.txt b/test/data/fle-4-no-qso.txt new file mode 100644 index 0000000..232c631 --- /dev/null +++ b/test/data/fle-4-no-qso.txt @@ -0,0 +1,7 @@ +date 2020-07-19 +mycall ON6ZQ/P +mysota ON/ON-018 + +cw +30m +1150