Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial CSV Parser code #1

Merged
merged 5 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: build

on:
push:
branches:
- main
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
- name: Execute Tests
run: make tests
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ build:
docker run --rm -v `pwd`:/build -w /build/functions/build/init tinygo/tinygo:0.25.0 tinygo build -o /build/functions/build/init.wasm -target wasi /build/functions/src/init/main.go
docker run --rm -v `pwd`:/build -w /build/functions/build/data/fetch tinygo/tinygo:0.25.0 tinygo build -o /build/functions/build/fetch.wasm -target wasi /build/functions/src/data/fetch/main.go

.PHONY: tests
tests:
## Run tests
mkdir -p coverage
go test -v -race -covermode=atomic -coverprofile=coverage/coverage.out ./...
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
madflojo marked this conversation as resolved.
Show resolved Hide resolved

docker-compose:
docker compose up

Expand Down
6 changes: 1 addition & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,4 @@ module github.com/tarmac-project/example-airport-lookup-go

go 1.21

require (
github.com/tarmac-project/tarmac/pkg/sdk v0.5.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/wapc/wapc-guest-tinygo v0.3.3 // indirect
)
require github.com/enescakir/emoji v1.0.0
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
github.com/tarmac-project/tarmac/pkg/sdk v0.5.0 h1:QKsEf6SXTYrJM9/B4cNoM4RS3/rzuViJaiutEcdSRZQ=
github.com/tarmac-project/tarmac/pkg/sdk v0.5.0/go.mod h1:UTKYV0QFdkJDgV2sJcnuCujVy49MCd8bgi2JmwviJ6E=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/wapc/wapc-guest-tinygo v0.3.3 h1:jLebiwjVSHLGnS+BRabQ6+XOV7oihVWAc05Hf1SbeR0=
github.com/wapc/wapc-guest-tinygo v0.3.3/go.mod h1:mzM3CnsdSYktfPkaBdZ8v88ZlfUDEy5Jh5XBOV3fYcw=
github.com/enescakir/emoji v1.0.0 h1:W+HsNql8swfCQFtioDGDHCHri8nudlK1n5p2rHCJoog=
github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0=
108 changes: 108 additions & 0 deletions pkg/airport/airport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package airport

import (
"fmt"
"github.com/enescakir/emoji"
)

// Airport is a struct that contains information about an airport.
type Airport struct {
// Continent is the continent the airport is located in.
Continent string `json:"continent"`

// Emoji is the emoji of the airport location. (Example: 🇺🇸, 🇨🇦, 🇬🇧, etc.)
Emoji string `json:"emoji"`

// ISOCountry is the ISO code of the country the airport is located in.
ISOCountry string `json:"iso_country"`

// ISORegion is the ISO code of the region the airport is located in.
ISORegion string `json:"iso_region"`

// LocalCode is the local code of the airport. This is a three letter code and is unique to each airport.
LocalCode string `json:"local_code"`

// Municipality is the municipality the airport is located in.
Municipality string `json:"municipality"`

// Name is the name of the airport.
Name string `json:"name"`

// Type is the type of airport (examples: small_airport, heliport, closed, etc.).
Type string `json:"type"`

// TypeEmoji is the emoji of the airport type (examples: 🛬, 🚁, 🚧, etc.).
TypeEmoji string `json:"type_emoji"`

// Status is the status of airport (examples: open, closed, etc.).
Status string `json:"status"`
}

var (
ErrMissingFields = fmt.Errorf("Missing required fields")
ErrUnknownCountry = fmt.Errorf("Unable to lookup country emoji")
)

// Validate validates the airport struct and returns the airport with the emoji and country flag set.
func Validate(a Airport) (Airport, error) {
var err error
// Validate Minimum Fields Exist
if a.LocalCode == "" || a.Name == "" || a.ISOCountry == "" {
return a, ErrMissingFields
}

// Set Airport Emoji
a, err = setTypeEmoji(a)
if err != nil {
return a, err
}

// Set Country Flag
a, err = setCountryFlag(a)
if err != nil {
return a, err
}

return a, nil
}

// setTypeEmoji sets the emoji for the airport type.
func setTypeEmoji(a Airport) (Airport, error) {
switch a.Type {
case "heliport":
a.TypeEmoji = emoji.Helicopter.String()
a.Status = "open"
case "small_airport":
a.TypeEmoji = emoji.SmallAirplane.String()
a.Status = "open"
case "medium_airport", "large_airport":
a.TypeEmoji = emoji.Airplane.String()
a.Status = "open"
case "seaplane_base":
a.TypeEmoji = emoji.Anchor.String()
a.Status = "open"
case "balloonport":
a.TypeEmoji = emoji.Balloon.String()
a.Status = "open"
case "closed", "unknown":
a.Type = "unknown"
a.TypeEmoji = emoji.Construction.String()
a.Status = "closed"
default:
a.TypeEmoji = emoji.QuestionMark.String()
a.Status = "unknown"
}

return a, nil
}

// setCountryFlag sets the emoji for the country the airport is located in.
func setCountryFlag(a Airport) (Airport, error) {
// Set the Country Emoji
flag, err := emoji.CountryFlag(a.ISOCountry)
if err != nil {
return a, ErrUnknownCountry
}
a.Emoji = flag.String()
return a, nil
}
196 changes: 196 additions & 0 deletions pkg/airport/airport_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package airport

import (
"reflect"
"testing"
)

type AirportTestCase struct {
name string
input Airport
expected Airport
err error
}

func TestAirport(t *testing.T) {
tt := []AirportTestCase{
{
name: "Basic Test",
input: Airport{
Name: "Test Airport",
LocalCode: "TST",
ISOCountry: "US",
},
expected: Airport{
Name: "Test Airport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "❓",
Status: "unknown",
},
},
{
name: "Missing name",
input: Airport{
LocalCode: "TST",
ISOCountry: "US",
},
err: ErrMissingFields,
},
{
name: "Unknown country",
input: Airport{
Name: "Test Airport",
LocalCode: "TST",
ISOCountry: "TST",
},
err: ErrUnknownCountry,
},
{
name: "Heliport",
input: Airport{
Name: "Test Heliport",
LocalCode: "TST",
ISOCountry: "US",
Type: "heliport",
},
expected: Airport{
Name: "Test Heliport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "🚁",
Status: "open",
Type: "heliport",
},
},
{
name: "Small Airport",
input: Airport{
Name: "Test Small Airport",
LocalCode: "TST",
ISOCountry: "US",
Type: "small_airport",
},
expected: Airport{
Name: "Test Small Airport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "🛩️",
Status: "open",
Type: "small_airport",
},
},
{
name: "Medium Airport",
input: Airport{
Name: "Test Medium Airport",
LocalCode: "TST",
ISOCountry: "US",
Type: "medium_airport",
},
expected: Airport{
Name: "Test Medium Airport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "✈️",
Status: "open",
Type: "medium_airport",
},
},
{
name: "Large Airport",
input: Airport{
Name: "Test Large Airport",
LocalCode: "TST",
ISOCountry: "US",
Type: "large_airport",
},
expected: Airport{
Name: "Test Large Airport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "✈️",
Status: "open",
Type: "large_airport",
},
},
{
name: "Balloonport",
input: Airport{
Name: "Test Balloonport",
LocalCode: "TST",
ISOCountry: "US",
Type: "balloonport",
},
expected: Airport{
Name: "Test Balloonport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
TypeEmoji: "🎈",
Status: "open",
Type: "balloonport",
},
},
{
name: "Seaplane Base",
input: Airport{
Name: "Test Seaplane Base",
LocalCode: "TST",
ISOCountry: "US",
Type: "seaplane_base",
},
expected: Airport{
Name: "Test Seaplane Base",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
Status: "open",
Type: "seaplane_base",
TypeEmoji: "⚓",
},
},
{
name: "Closed Airport",
input: Airport{
Name: "Test Closed Airport",
LocalCode: "TST",
ISOCountry: "US",
Type: "closed",
},
expected: Airport{
Name: "Test Closed Airport",
LocalCode: "TST",
ISOCountry: "US",
Emoji: "🇺🇸",
Status: "closed",
Type: "unknown",
TypeEmoji: "🚧",
},
},
}

for _, tc := range tt {
t.Run("Airport Validation: "+tc.name, func(t *testing.T) {
result, err := Validate(tc.input)
if err != nil {
if tc.err == nil {
t.Fatalf("Unexpected error: %v", err)
}
if tc.err != err {
t.Fatalf("Expected error %v, got %v", tc.err, err)
}
return
}

if !reflect.DeepEqual(result, tc.expected) {
t.Errorf("Expected %v, got %v", tc.expected, result)
}
})
}
}
Loading