Add day increment feature

pull/52/head
Jean-Marc MEESSEN 4 years ago committed by GitHub
parent ebe782ead0
commit 51bea8d698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,7 +2,12 @@
## v0.1.2
* Correctly process of optional WWFF keyword(issue #38)
* DATE keyword is now optional
* Date can have several delimiter ("-", "/", ".", or " ")
* Partial dates can be entered ("20-9-6" => "2020-09-06")
* The new (FLE v3) "DAY" keyword is now supported (increment is 10 max)
* Date, band, and mode can be specified on a same line, even with a QSO
* Correctly process of optional WWFF keyword
* Correct some typos
## Previous releases

@ -80,7 +80,6 @@ func Test_buildAdif(t *testing.T) {
"<STATION_CALLSIGN:8>ON4KJM/P <CALL:5>ON4LY <QSO_DATE:8>20200524 <TIME_ON:4>1312 <BAND:3>20m <MODE:2>CW <RST_SENT:3>559 <RST_RCVD:3>599 <MY_SIG:4>WWFF <MY_SIG_INFO:9>ONFF-0259 <OPERATOR:6>ON4KJM <MY_GRIDSQUARE:6>JO40eu <EOR>",
}
type args struct {
fullLog []LogLine
isWWFF bool

@ -61,8 +61,6 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL
regexpHeaderMyGrid := regexp.MustCompile("(?i)^mygrid ")
regexpHeaderQslMsg := regexp.MustCompile("(?i)^qslmsg ")
regexpHeaderNickname := regexp.MustCompile("(?i)^nickname ")
regexpHeaderDateMarker := regexp.MustCompile("(?i)^date ")
regexpDatePattern := regexp.MustCompile("^(\\d{2}|\\d{4})[-/ .]\\d{1,2}[-/ .]\\d{1,2}$")
headerMyCall := ""
headerOperator := ""
@ -71,7 +69,7 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL
headerMyGrid := ""
headerQslMsg := ""
headerNickname := ""
headerDate := ""
//headerDate := ""
lineCount := 0
wrkTimeBlock := InferTimeBlock{}
@ -218,42 +216,42 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL
continue
}
// Date with keyword
if regexpHeaderDateMarker.MatchString(eachline) {
errorMsg := ""
myDateList := regexpHeaderDateMarker.Split(eachline, -1)
if len(myDateList[1]) > 0 {
normalizedDate := ""
normalizedDate, errorMsg = NormalizeDate(myDateList[1])
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
} else {
headerDate, errorMsg = ValidateDate(normalizedDate)
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, myDateList[1], errorMsg))
}
}
}
//If there is no data after the marker, we just skip the data.
continue
}
//Date, apparently alone on a line?
if regexpDatePattern.MatchString(eachline) {
//We probably have a date, let's normalize it
errorMsg := ""
normalizedDate := ""
normalizedDate, errorMsg = NormalizeDate(eachline)
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
} else {
headerDate, errorMsg = ValidateDate(normalizedDate)
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
}
}
continue
}
// // Date with keyword
// if regexpHeaderDateMarker.MatchString(eachline) {
// errorMsg := ""
// myDateList := regexpHeaderDateMarker.Split(eachline, -1)
// if len(myDateList[1]) > 0 {
// normalizedDate := ""
// normalizedDate, errorMsg = NormalizeDate(myDateList[1])
// if len(errorMsg) != 0 {
// errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
// } else {
// headerDate, errorMsg = ValidateDate(normalizedDate)
// if len(errorMsg) != 0 {
// errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, myDateList[1], errorMsg))
// }
// }
// }
// //If there is no data after the marker, we just skip the data.
// continue
// }
// //Date, apparently alone on a line?
// if regexpDatePattern.MatchString(eachline) {
// //We probably have a date, let's normalize it
// errorMsg := ""
// normalizedDate := ""
// normalizedDate, errorMsg = NormalizeDate(eachline)
// if len(errorMsg) != 0 {
// errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
// } else {
// headerDate, errorMsg = ValidateDate(normalizedDate)
// if len(errorMsg) != 0 {
// errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, eachline, errorMsg))
// }
// }
// continue
// }
// ****
// ** Process the data block
@ -267,7 +265,7 @@ func LoadFile(inputFilename string, isInterpolateTime bool) (filleFullLog []LogL
previousLogLine.MyGrid = headerMyGrid
previousLogLine.QSLmsg = headerQslMsg //previousLogLine.QslMsg is redundant
previousLogLine.Nickname = headerNickname
previousLogLine.Date = headerDate
//previousLogLine.Date = headerDate
//parse a line
logline, errorLine := ParseLine(eachline, previousLogLine)

@ -199,6 +199,188 @@ func TestLoadFile_happyCase_date(t *testing.T) {
os.Remove(temporaryDataFileName)
}
func TestLoadFile_happyCase_date2(t *testing.T) {
//Given
dataArray := make([]string, 0)
dataArray = append(dataArray, "# Header")
dataArray = append(dataArray, "myCall on4kjm/p")
dataArray = append(dataArray, "operator on4kjm")
dataArray = append(dataArray, "nickname Portable")
dataArray = append(dataArray, " ")
dataArray = append(dataArray, " #Log")
dataArray = append(dataArray, "20/5/23")
dataArray = append(dataArray, "40m cw 0950 ik5zve/5 9 5")
dataArray = append(dataArray, "on6zq")
dataArray = append(dataArray, "0954 on4do")
dataArray = append(dataArray, "20-05-25 20m ssb 1000 on4up")
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 = "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)
}
// "20-05-25 20m 1000 on4up")
expectedValue = "2020-05-25"
if loadedLogFile[3].Date != expectedValue {
t.Errorf("Not the expected Date[3] value: %s (expecting %s)", loadedLogFile[3].Time, expectedValue)
}
expectedValue = "1000"
if loadedLogFile[3].Time != expectedValue {
t.Errorf("Not the expected Time[3] value: %s (expecting %s)", loadedLogFile[3].Time, expectedValue)
}
expectedValue = "20m"
if loadedLogFile[3].Band != expectedValue {
t.Errorf("Not the expected Band[3] value: %s (expecting %s)", loadedLogFile[3].Band, expectedValue)
}
expectedValue = "ON4UP"
if loadedLogFile[3].Call != expectedValue {
t.Errorf("Not the expected Call[3] value: %s (expecting %s)", loadedLogFile[3].Call, expectedValue)
}
//Clean Up
os.Remove(temporaryDataFileName)
}
func TestLoadFile_happyCase_day(t *testing.T) {
//Given
dataArray := make([]string, 0)
dataArray = append(dataArray, "# Header")
dataArray = append(dataArray, "myCall on4kjm/p")
dataArray = append(dataArray, "operator on4kjm")
dataArray = append(dataArray, "nickname Portable")
dataArray = append(dataArray, " ")
dataArray = append(dataArray, " #Log")
dataArray = append(dataArray, "20/5/23")
dataArray = append(dataArray, "40m cw 0950 ik5zve/5 9 5")
dataArray = append(dataArray, "on6zq")
dataArray = append(dataArray, "0954 on4do")
dataArray = append(dataArray, "day ++ 20m 1000 on4up")
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 = "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)
}
// "20-05-25 20m 1000 on4up")
expectedValue = "2020-05-25"
if loadedLogFile[3].Date != expectedValue {
t.Errorf("Not the expected Date[3] value: %s (expecting %s)", loadedLogFile[3].Time, expectedValue)
}
expectedValue = "1000"
if loadedLogFile[3].Time != expectedValue {
t.Errorf("Not the expected Time[3] value: %s (expecting %s)", loadedLogFile[3].Time, expectedValue)
}
expectedValue = "20m"
if loadedLogFile[3].Band != expectedValue {
t.Errorf("Not the expected Band[3] value: %s (expecting %s)", loadedLogFile[3].Band, expectedValue)
}
expectedValue = "ON4UP"
if loadedLogFile[3].Call != expectedValue {
t.Errorf("Not the expected Call[3] value: %s (expecting %s)", loadedLogFile[3].Call, expectedValue)
}
//Clean Up
os.Remove(temporaryDataFileName)
}
func TestLoadFile_bad_date(t *testing.T) {
//Given
@ -280,7 +462,6 @@ func TestLoadFile_bad_date(t *testing.T) {
os.Remove(temporaryDataFileName)
}
func TestLoadFile_wrongHeader(t *testing.T) {
//Given

@ -59,8 +59,12 @@ var regexpIsOMname = regexp.MustCompile("^@")
var regexpIsGridLoc = regexp.MustCompile("^#")
var regexpIsRst = regexp.MustCompile("^[\\d]{1,3}$")
var regexpIsFreq = regexp.MustCompile("^[\\d]+\\.[\\d]+$")
var regexpIsSotaKeyWord = regexp.MustCompile("(?i)^sota")
var regexpIsWwffKeyWord = regexp.MustCompile("(?i)^wwff")
var regexpIsSotaKeyWord = regexp.MustCompile("(?i)^sota$")
var regexpIsWwffKeyWord = regexp.MustCompile("(?i)^wwff$")
var regexpDatePattern = regexp.MustCompile("^(\\d{2}|\\d{4})[-/ .]\\d{1,2}[-/ .]\\d{1,2}$")
var regexpIsDateKeyWord = regexp.MustCompile("(?i)^date$")
var regexpDayIncrementPattern = regexp.MustCompile("^\\+*$")
var regexpIsDayKeyword = regexp.MustCompile("(?i)^day$")
// ParseLine cuts a FLE line into useful bits
func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg string) {
@ -119,6 +123,46 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
continue
}
//Date?
if regexpDatePattern.MatchString(element) {
//We probably have a date, let's normalize it
errorTxt := ""
normalizedDate := ""
normalizedDate, errorTxt = NormalizeDate(element)
if len(errorTxt) != 0 {
logLine.Date = normalizedDate
errorMsg = errorMsg + fmt.Sprintf("Invalid Date: %s (%s)", element, errorTxt)
} else {
logLine.Date, errorTxt = ValidateDate(normalizedDate)
if len(errorTxt) != 0 {
errorMsg = errorMsg + fmt.Sprintf("Error %s", errorTxt)
}
}
continue
}
// The date keyword is not really useful, skip it
if regexpIsDateKeyWord.MatchString(element) {
continue
}
//Skip the "day" keyword
if regexpIsDayKeyword.MatchString(element) {
continue
}
//Scan the + part
if regexpDayIncrementPattern.MatchString(element) {
increment := len(element)
fmt.Println(logLine.Date)
newDate, dateError := IncrementDate(logLine.Date, increment)
if dateError != "" {
errorMsg = errorMsg + fmt.Sprintf(dateError)
}
logLine.Date = newDate
continue
}
// Is it a band?
isBandElement, bandLowerLimit, bandUpperLimit, _ := IsBand(element)
if isBandElement {

@ -152,6 +152,36 @@ func TestParseLine(t *testing.T) {
args{inputStr: "1230 oe6cud/p onff-0258", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE", WWFF: "ONFF-0258"}, "",
},
{
"date processing",
args{inputStr: "20.09.7 1230 oe6cud/p onff-0258", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "2020-09-07", Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE", WWFF: "ONFF-0258"}, "",
},
{
"date processing (with keyword)",
args{inputStr: "Date 20.09.7 1230 oe6cud/p onff-0258", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "2020-09-07", Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE", WWFF: "ONFF-0258"}, "",
},
{
"date processing - validation error",
args{inputStr: "20.09.34 1230 oe6cud/p onff-0258", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "*2020-09-34", Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE", WWFF: "ONFF-0258"}, "Error parsing time \"2020-09-34\": day out of range",
},
{
"date processing - day ",
args{inputStr: "day ++ 1230 oe6cud/p ", previousLine: LogLine{Date: "2020-09-05", Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "2020-09-07", Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE"}, "",
},
{
"date processing - day (error) ",
args{inputStr: "day +++++++++++ 1230 oe6cud/p ", previousLine: LogLine{Date: "2020-09-05", Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "*2020-09-05", Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "59", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE"}, "Invalid day increment, expecting smaller or equal to 10",
},
{
"date band and mode on the same line)",
args{inputStr: "Date 20.09.7 40m cw 1230 oe6cud/p onff-0258", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Date: "2020-09-07", Mode: "CW", Band: "40m", BandLowerLimit: 7.0, BandUpperLimit: 7.3, Call: "OE6CUD/P", Time: "1230", ActualTime: "1230", RSTsent: "599", RSTrcvd: "599", ModeType: "CW", WWFF: "ONFF-0258"}, "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

@ -142,7 +142,6 @@ func NormalizeDate(inputStr string) (date, errorMsg string) {
return "*" + inputStr, errorMsg
}
//complete the numbers if shorter than expected ("20" for the first and "0" for the two next)
year := s[0]
if len(year) == 2 {
@ -194,6 +193,29 @@ func ValidateDate(inputStr string) (ref, errorMsg string) {
return wrongInputStr, fmt.Sprint(err)
}
//IncrementDate will increment the supplied date by the specified increment. It returns the new date.
func IncrementDate(date string, increment int) (newdate string, err string) {
if date == "" {
return "", "No date to increment"
}
if increment < 1 {
return "*" + date, "Invalid day increment, expecting greater or equal to 1"
}
if 10 < increment {
return "*" + date, "Invalid day increment, expecting smaller or equal to 10"
}
const RFC3339FullDate = "2006-01-02"
convertedTime, timeErr := time.Parse(RFC3339FullDate, date)
if timeErr != nil {
return "*" + date, "(Internal error) error " + fmt.Sprint(timeErr)
}
// the number of days specified in increment
newDate := convertedTime.AddDate(0, 0, increment)
return newDate.Format(RFC3339FullDate), ""
}
//IsBand retuns true if the passed input string is a valid string
func IsBand(inputStr string) (result bool, lowerLimit, upperLimit float64, altBandName string) {
switch strings.ToLower(inputStr) {

@ -455,3 +455,53 @@ func TestNormalizeDate(t *testing.T) {
})
}
}
func TestIncrementDate(t *testing.T) {
type args struct {
date string
increment int
}
tests := []struct {
name string
args args
wantNewdate string
wantErr string
}{
{
"No date",
args{date: "", increment: 2},
"", "No date to increment",
},
{
"increment below 0",
args{date: "2020-09-05", increment: 0},
"*2020-09-05", "Invalid day increment, expecting greater or equal to 1",
},
{
"increment above 10",
args{date: "2020-09-05", increment: 11},
"*2020-09-05", "Invalid day increment, expecting smaller or equal to 10",
},
{
"Invalid date",
args{date: "2020-09-32", increment: 2},
"*2020-09-32", "(Internal error) error parsing time \"2020-09-32\": day out of range",
},
{
"happy case",
args{date: "2020-09-05", increment: 2},
"2020-09-07", "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotNewdate, gotErr := IncrementDate(tt.args.date, tt.args.increment)
if gotNewdate != tt.wantNewdate {
t.Errorf("IncrementDate() gotNewdate = %v, want %v", gotNewdate, tt.wantNewdate)
}
if gotErr != tt.wantErr {
t.Errorf("IncrementDate() gotErr = %v, want %v", gotErr, tt.wantErr)
}
})
}
}

Loading…
Cancel
Save