Skip to content

Commit

Permalink
validate: warn if latitude is set but not longitude or vice versa
Browse files Browse the repository at this point in the history
  • Loading branch information
flwyd committed Feb 2, 2025
1 parent 0b0cf5c commit 3ce8d78
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ input.
* `validate --required-fields` supports conditionals (`--if`, `--if-not`,
`--or-if`, `--or-if-not`) to determine which records must have certain fields
set. All records are checked for data type validity, e.g. number formatting.
* `validate` will warn if `LAT` or `LON` is set but the other one isn’t;
likewise for `MY_LAT`/`MY_LON`. It’s possible to know latitude without also
knowing longitude, but modern technology usually gives both together, so you
probably had a copy-paste error.

[CQ Zones](https://mapability.com/ei8ic/maps/cqzone.php) and
[ITU Zones](https://mapability.com/ei8ic/maps/ituzone.php):
Expand Down
14 changes: 14 additions & 0 deletions adif/spec/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,20 @@ func ValidateLocation(val string, f Field, ctx ValidationContext) Validation {
} else if !between(min, 0.0, 60.0) {
return errorf("%s minutes out of range in %q", f.Name, val)
}
var other string
switch f.Name {
case LatField.Name:
other = LonField.Name
case LonField.Name:
other = LatField.Name
case MyLatField.Name:
other = MyLonField.Name
case MyLonField.Name:
other = MyLatField.Name
}
if other != "" && ctx.FieldValue(other) == "" {
return warningf("%s is set but %s is not set; latitude and longitude usually come together", f.Name, other)
}
return valid()
}

Expand Down
50 changes: 34 additions & 16 deletions adif/spec/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,31 @@
package spec

import (
"strings"
"testing"
"time"
)

type validateTest struct {
field Field
value string
want Validity
field Field
value string
want Validity
others []validateTest
}

var emptyCtx = ValidationContext{FieldValue: func(name string) string { return "" }}

func validateTestCtx(v validateTest) ValidationContext {
return ValidationContext{FieldValue: func(name string) string {
for _, o := range v.others {
if strings.EqualFold(name, o.field.Name) {
return o.value
}
}
return ""
}}
}

func testValidator(t *testing.T, tc validateTest, ctx ValidationContext, funcname string) {
t.Helper()
v := TypeValidators[tc.field.Type.Name]
Expand Down Expand Up @@ -721,18 +734,18 @@ func TestValidateLocation(t *testing.T) {
tests := []validateTest{
{field: LatField, value: "", want: Valid},
{field: LonField, value: "", want: Valid},
{field: LatField, value: "N000 00.000", want: Valid},
{field: LatField, value: "S000 00.000", want: Valid},
{field: LonField, value: "E000 00.000", want: Valid},
{field: LonField, value: "W000 00.000", want: Valid},
{field: MyLatField, value: "N001 00.000", want: Valid},
{field: MyLatField, value: "S090 00.000", want: Valid},
{field: MyLonField, value: "E009 00.000", want: Valid},
{field: MyLonField, value: "W180 00.000", want: Valid},
{field: LatField, value: "N012 34.567", want: Valid},
{field: LatField, value: "S023 59.999", want: Valid},
{field: LonField, value: "E000 00.001", want: Valid},
{field: LonField, value: "W120 30.050", want: Valid},
{field: LatField, value: "N000 00.000", want: Valid, others: []validateTest{{field: LonField, value: "E000 00.000"}}},
{field: LatField, value: "S000 00.000", want: Valid, others: []validateTest{{field: LonField, value: "W000 00.000"}}},
{field: LonField, value: "E000 00.000", want: Valid, others: []validateTest{{field: LatField, value: "N000 00.000"}}},
{field: LonField, value: "W000 00.000", want: Valid, others: []validateTest{{field: LatField, value: "S000 00.000"}}},
{field: MyLatField, value: "N001 00.000", want: Valid, others: []validateTest{{field: MyLonField, value: "W123 45.678"}}},
{field: MyLatField, value: "S090 00.000", want: Valid, others: []validateTest{{field: MyLonField, value: "E123 45.678"}}},
{field: MyLonField, value: "E009 00.000", want: Valid, others: []validateTest{{field: MyLatField, value: "S012 34.567"}}},
{field: MyLonField, value: "W180 00.000", want: Valid, others: []validateTest{{field: MyLatField, value: "S012 34.567"}}},
{field: LatField, value: "N012 34.567", want: Valid, others: []validateTest{{field: LonField, value: "E000 00.000"}}},
{field: LatField, value: "S023 59.999", want: Valid, others: []validateTest{{field: LonField, value: "W000 00.000"}}},
{field: LonField, value: "E000 00.001", want: Valid, others: []validateTest{{field: LatField, value: "S000 00.000"}}},
{field: LonField, value: "W120 30.050", want: Valid, others: []validateTest{{field: LatField, value: "N000 00.000"}}},
{field: LatField, value: "Equator", want: InvalidError},
{field: LonField, value: "Greenwich", want: InvalidError},
{field: LatField, value: "X012 34.567", want: InvalidError},
Expand All @@ -749,9 +762,14 @@ func TestValidateLocation(t *testing.T) {
{field: MyLonField, value: "123 45.678E", want: InvalidError},
{field: MyLonField, value: `123 45' 54.321"`, want: InvalidError},
{field: MyLonField, value: `-123° 45' 54.321"`, want: InvalidError},
// Warning if one coordinate field is set but not the other
{field: LatField, value: "N012 34.567", want: InvalidWarning},
{field: LonField, value: "E012 34.567", want: InvalidWarning},
{field: MyLatField, value: "N012 34.567", want: InvalidWarning},
{field: MyLonField, value: "E012 34.567", want: InvalidWarning},
}
for _, tc := range tests {
testValidator(t, tc, emptyCtx, "ValidateLocation")
testValidator(t, tc, validateTestCtx(tc), "ValidateLocation")
}
}

Expand Down

0 comments on commit 3ce8d78

Please sign in to comment.