Skip to content

Commit 32faa54

Browse files
committed
add tests
1 parent 17282a0 commit 32faa54

3 files changed

Lines changed: 204 additions & 0 deletions

File tree

.github/workflows/test.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: 'Test'
2+
3+
on:
4+
push: {}
5+
6+
jobs:
7+
test:
8+
name: 'Test'
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: 'Checkout'
12+
uses: actions/checkout@v4
13+
- name: 'Setup go'
14+
uses: actions/setup-go@v5
15+
with:
16+
go-version-file: 'go.mod'
17+
- name: 'Test'
18+
run: 'go test ./...'

data_test.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package reference_data
2+
3+
import (
4+
_ "embed"
5+
"encoding/csv"
6+
"errors"
7+
"fmt"
8+
"io"
9+
"iter"
10+
"strings"
11+
"testing"
12+
)
13+
14+
//go:embed aircraft_aliases.csv
15+
var aliases string
16+
17+
//go:embed aircraft_families.csv
18+
var families string
19+
20+
//go:embed aircraft_types.csv
21+
var types string
22+
23+
type readerAndIdColumn struct {
24+
reader io.Reader
25+
idColumn string
26+
allowNull bool
27+
}
28+
29+
func TestIdsAreUnique(t *testing.T) {
30+
testIdsAreUnique(t, readerAndIdColumn{reader: strings.NewReader(aliases), idColumn: "alias"})
31+
testIdsAreUnique(t, readerAndIdColumn{reader: strings.NewReader(families), idColumn: "id"})
32+
testIdsAreUnique(t, readerAndIdColumn{reader: strings.NewReader(types), idColumn: "id"})
33+
testIdsAreUnique(t, readerAndIdColumn{reader: strings.NewReader(types), idColumn: "iata"}, readerAndIdColumn{reader: strings.NewReader(families), idColumn: "iata", allowNull: true})
34+
}
35+
36+
func TestAliasesXor(t *testing.T) {
37+
var err error
38+
for line, row := range readCsv(strings.NewReader(aliases), &err) {
39+
isType := row["aircraft_type"] != ""
40+
isFamily := row["aircraft_family"] != ""
41+
42+
if isType && isFamily {
43+
t.Fatalf("both type and family are set in line %d", line)
44+
return
45+
} else if !isType && !isFamily {
46+
t.Fatalf("neither type nor family are set in line %d", line)
47+
return
48+
}
49+
}
50+
51+
if err != nil {
52+
t.Fatal(err)
53+
return
54+
}
55+
}
56+
57+
func TestReferences(t *testing.T) {
58+
expectedFamilyIds := make(map[string]struct{})
59+
expectedAircraftIds := make(map[string]struct{})
60+
61+
var err error
62+
for _, row := range readCsv(strings.NewReader(aliases), &err) {
63+
if aircraftId := row["aircraft_type"]; aircraftId != "" {
64+
expectedAircraftIds[aircraftId] = struct{}{}
65+
}
66+
67+
if familyId := row["aircraft_family"]; familyId != "" {
68+
expectedFamilyIds[familyId] = struct{}{}
69+
}
70+
}
71+
72+
if err != nil {
73+
t.Fatal(err)
74+
return
75+
}
76+
77+
for _, row := range readCsv(strings.NewReader(types), &err) {
78+
if familyId := row["family_id"]; familyId != "" {
79+
expectedFamilyIds[familyId] = struct{}{}
80+
}
81+
82+
delete(expectedAircraftIds, row["id"])
83+
}
84+
85+
if err != nil {
86+
t.Fatal(err)
87+
return
88+
}
89+
90+
if len(expectedAircraftIds) > 0 {
91+
t.Fatalf("missing expected aircraft ids: %v", expectedAircraftIds)
92+
return
93+
}
94+
95+
for _, row := range readCsv(strings.NewReader(families), &err) {
96+
if familyId := row["parent_family"]; familyId != "" {
97+
expectedFamilyIds[familyId] = struct{}{}
98+
}
99+
}
100+
101+
if err != nil {
102+
t.Fatal(err)
103+
return
104+
}
105+
106+
for _, row := range readCsv(strings.NewReader(families), &err) {
107+
delete(expectedFamilyIds, row["id"])
108+
}
109+
110+
if err != nil {
111+
t.Fatal(err)
112+
return
113+
}
114+
115+
if len(expectedFamilyIds) > 0 {
116+
t.Fatalf("missing expected family ids: %v", expectedAircraftIds)
117+
return
118+
}
119+
}
120+
121+
func testIdsAreUnique(t *testing.T, readersAndIdColumns ...readerAndIdColumn) {
122+
var err error
123+
ids := make(map[string]struct{})
124+
for _, readerAndIdColumn := range readersAndIdColumns {
125+
for line, row := range readCsv(readerAndIdColumn.reader, &err) {
126+
id := row[readerAndIdColumn.idColumn]
127+
if id == "" {
128+
if !readerAndIdColumn.allowNull {
129+
t.Fatalf("%s is null in line %d", readerAndIdColumn.idColumn, line)
130+
}
131+
} else {
132+
if _, ok := ids[id]; ok {
133+
t.Fatalf("duplicate %s: %q in line %d", readerAndIdColumn.idColumn, id, line)
134+
return
135+
}
136+
137+
ids[id] = struct{}{}
138+
}
139+
}
140+
}
141+
142+
if err != nil {
143+
t.Fatal(err)
144+
return
145+
}
146+
}
147+
148+
func readCsv(reader io.Reader, outErr *error) iter.Seq2[int, map[string]string] {
149+
return func(yield func(int, map[string]string) bool) {
150+
r := csv.NewReader(reader)
151+
headers, err := r.Read()
152+
if err != nil {
153+
*outErr = fmt.Errorf("failed to read header: %w", err)
154+
return
155+
}
156+
157+
line := 1
158+
for {
159+
record, err := r.Read()
160+
if err != nil {
161+
if errors.Is(err, io.EOF) {
162+
break
163+
}
164+
165+
*outErr = err
166+
break
167+
}
168+
169+
row := make(map[string]string)
170+
for i, colName := range headers {
171+
if i < len(record) {
172+
row[colName] = record[i]
173+
}
174+
}
175+
176+
if !yield(line, row) {
177+
break
178+
}
179+
180+
line++
181+
}
182+
}
183+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/explore-flights/reference-data
2+
3+
go 1.24.4

0 commit comments

Comments
 (0)