Improve tests coverage

pull/29/head
Jean-Marc MEESSEN 4 years ago committed by GitHub
parent 0b9fb5bc78
commit 3eeda8fd79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

@ -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.")
}

@ -1,50 +0,0 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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)
}
}
}

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

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

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"

@ -2,6 +2,22 @@ package fleprocess
import "testing"
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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

@ -0,0 +1,103 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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
}

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

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

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"

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

@ -0,0 +1,185 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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)
}
})
}
}

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"

@ -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,7 +317,7 @@ 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))

@ -0,0 +1,373 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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()
}

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"}},

@ -1,5 +1,21 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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"
)

@ -0,0 +1,53 @@
package fleprocess
import (
"bufio"
"fmt"
"os"
)
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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)
}
}

@ -0,0 +1,67 @@
package fleprocess
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
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)
}

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

@ -0,0 +1,7 @@
date 2020-07-19
mycall ON6ZQ/P
mysota ON/ON-018
cw
30m
1150
Loading…
Cancel
Save