chore: Remove unused fields in FPL and DEP structs
The code changes remove the unused `SurveillanceEquipment` field in the `FPL` struct and the `TelegramCategory` field in the `DEP` struct. These fields are no longer needed and can be safely removed. This commit improves code cleanliness and reduces unnecessary complexity.
This commit is contained in:
@@ -94,7 +94,7 @@ const (
|
|||||||
// - remark: Matches remarks, capturing any characters in this segment.
|
// - remark: Matches remarks, capturing any characters in this segment.
|
||||||
//
|
//
|
||||||
// The regular expression uses named capture groups for each segment, allowing for easy extraction of specific information from a matched flight plan string.
|
// The regular expression uses named capture groups for each segment, allowing for easy extraction of specific information from a matched flight plan string.
|
||||||
fplPatternString = `^\((?P<type>[A-Z]{3})\-(?P<number>[A-Z]+\d+)\-(?P<indicator>[A-Z]{2})(?:.*\s*)?\-(?P<aircraft>[A-Z]+\d+\/?[A-Z]?)\s*\-(?P<surve>.*)\s*\-(?P<departure>[A-Z]{4})(?P<departure_time>\d{4})\s*\-(?P<speed>[A-Z]+\d+)(?P<level>[A-Z0-9]+)\s(?P<route>.*)\s*\-(?P<destination>[A-Z]{4})(?P<estt>\d{4})\s(?P<alter>[A-Z]{4})\s*\-(?P<pbn>PBN\/[A-Z0-9]+)\s(?P<nav>NAV\/\w+)\sREG\/(?P<reg>[A-Z0-9]+)\sEET\/(?P<eet>\w{4}\d{4})\sSEL\/(?P<sel>\w+)\sPER\/(?P<performance>\w)\sRIF\/(?P<rif>\w+\s[A-Z0-9]+\s[A-Z]+)\s*RMK\/(?P<remark>.*)\)$`
|
fplPatternString = `\((?P<type>[A-Z]{3})\-(?P<number>[A-Z]+\d+)\-(?P<indicator>[A-Z]{2})(.*\n)?(.*\n)?\-(?P<aircraft>[A-Z]+\d+\/?[A-Z]?)\s*\-(?P<surve>.*)(.*\n)?\-(?P<departure>[A-Z]{4})(?P<departure_time>\d{4})(.*\n)?\-(?P<speed>[A-Z]+\d+)(?P<level>[A-Z0-9]+)\s(?P<route>.*)(.*\n)?\-(?P<destination>[A-Z]{4})(?P<estt>\d{4})\s(?P<alter>[A-Z]{4})(.*\n)?\-(?P<pbn>PBN\/[A-Z0-9]+)\s(?P<nav>NAV\/\w+)\sREG\/(?P<reg>[A-Z0-9]+)\sEET\/(?P<eet>\w{4}\d{4})\sSEL\/(?P<sel>\w+)\sPER\/(?P<performance>\w)\sRIF\/(?P<rif>\w+\s[A-Z0-9]+\s[A-Z]+)\s*RMK\/(?P<remark>.*)\)$`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize the bodyPatterns map
|
// Initialize the bodyPatterns map
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ Description: This field contains any additional relevant information. It is opti
|
|||||||
*/
|
*/
|
||||||
// DEP 电报体中的起飞报文结构
|
// DEP 电报体中的起飞报文结构
|
||||||
type DEP struct {
|
type DEP struct {
|
||||||
TelegramCategory string `json:"telegram_category"` // 电报类别
|
Category string `json:"category"` // 电报类别
|
||||||
AircraftID string `json:"aircraft_id"` // 航空器识别标志
|
AircraftID string `json:"aircraft_id"` // 航空器识别标志
|
||||||
SSRModeAndCode string `json:"ssr_mode_and_code,omitempty"` // SSR 模式及编码(可选)
|
SSRModeAndCode string `json:"ssr_mode_and_code,omitempty"` // SSR 模式及编码(可选)
|
||||||
DepartureAirport string `json:"departure_airport"` // 起飞机场
|
DepartureAirport string `json:"departure_airport"` // 起飞机场
|
||||||
@@ -65,7 +65,7 @@ type DEP struct {
|
|||||||
|
|
||||||
// Validate validates the DEP struct fields
|
// Validate validates the DEP struct fields
|
||||||
func (d *DEP) Validate() error {
|
func (d *DEP) Validate() error {
|
||||||
if d.TelegramCategory == "" {
|
if d.Category == "" {
|
||||||
return fmt.Errorf("telegram category is required")
|
return fmt.Errorf("telegram category is required")
|
||||||
}
|
}
|
||||||
if d.AircraftID == "" {
|
if d.AircraftID == "" {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ var _ = Describe("DEP", func() {
|
|||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
original = DEP{
|
original = DEP{
|
||||||
TelegramCategory: "DEP",
|
Category: "DEP",
|
||||||
AircraftID: "ABCD1234",
|
AircraftID: "ABCD1234",
|
||||||
SSRModeAndCode: "A1234",
|
SSRModeAndCode: "A1234",
|
||||||
DepartureAirport: "JFK",
|
DepartureAirport: "JFK",
|
||||||
@@ -45,7 +45,7 @@ var _ = Describe("DEP", func() {
|
|||||||
|
|
||||||
It("should fail validation for missing required fields", func() {
|
It("should fail validation for missing required fields", func() {
|
||||||
invalidDEP := DEP{
|
invalidDEP := DEP{
|
||||||
TelegramCategory: "DEP",
|
Category: "DEP",
|
||||||
// AircraftID is missing
|
// AircraftID is missing
|
||||||
DepartureAirport: "JFK",
|
DepartureAirport: "JFK",
|
||||||
DepartureTime: "150405",
|
DepartureTime: "150405",
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ type FPL struct {
|
|||||||
AlternateAirport string `json:"alternate_airport,omitempty"` // 目的地备降机场(可选): Alternate airport (e.g., 'ZBYN').
|
AlternateAirport string `json:"alternate_airport,omitempty"` // 目的地备降机场(可选): Alternate airport (e.g., 'ZBYN').
|
||||||
OtherInfo string `json:"other_info,omitempty"` // 其他信息(可选): Other information.
|
OtherInfo string `json:"other_info,omitempty"` // 其他信息(可选): Other information.
|
||||||
SupplementaryInfo string `json:"supplementary_info,omitempty"` // 补充信息(可选): Supplementary information.
|
SupplementaryInfo string `json:"supplementary_info,omitempty"` // 补充信息(可选): Supplementary information.
|
||||||
SurveillanceEquipment string `json:"surveillance_equipment"` // 监视设备信息: Surveillance equipment information (e.g., 'SDE3FGHIJ4J5M1RWY').
|
|
||||||
EstimatedArrivalTime string `json:"estimated_arrival_time"` // 预计到达时间: Estimated time of arrival (e.g., '0153').
|
EstimatedArrivalTime string `json:"estimated_arrival_time"` // 预计到达时间: Estimated time of arrival (e.g., '0153').
|
||||||
PBN string `json:"pbn"` // 性能导航: Performance-based navigation equipment (e.g., 'A1B2B3B4B5D1L1').
|
PBN string `json:"pbn"` // 性能导航: Performance-based navigation equipment (e.g., 'A1B2B3B4B5D1L1').
|
||||||
NavigationEquipment string `json:"navigation_equipment"` // 导航设备: Navigation equipment (e.g., 'NAV/ABAS').
|
NavigationEquipment string `json:"navigation_equipment"` // 导航设备: Navigation equipment (e.g., 'NAV/ABAS').
|
||||||
@@ -98,9 +97,6 @@ func (f *FPL) Validate() error {
|
|||||||
if f.DestinationAndTotalTime == "" {
|
if f.DestinationAndTotalTime == "" {
|
||||||
return fmt.Errorf("destination and total time is required")
|
return fmt.Errorf("destination and total time is required")
|
||||||
}
|
}
|
||||||
if f.SurveillanceEquipment == "" {
|
|
||||||
return fmt.Errorf("surveillance equipment is required")
|
|
||||||
}
|
|
||||||
if f.EstimatedArrivalTime == "" {
|
if f.EstimatedArrivalTime == "" {
|
||||||
return fmt.Errorf("estimated arrival time is required")
|
return fmt.Errorf("estimated arrival time is required")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ var _ = Describe("FPL", func() {
|
|||||||
AlternateAirport: "SFO", // Example alternate airport
|
AlternateAirport: "SFO", // Example alternate airport
|
||||||
OtherInfo: "Test flight",
|
OtherInfo: "Test flight",
|
||||||
SupplementaryInfo: "Supplementary information",
|
SupplementaryInfo: "Supplementary information",
|
||||||
SurveillanceEquipment: "SDE3FGHIJ4J5M1RWY",
|
|
||||||
EstimatedArrivalTime: "0153", // Example estimated arrival time
|
EstimatedArrivalTime: "0153", // Example estimated arrival time
|
||||||
PBN: "A1B2B3B4B5D1L1",
|
PBN: "A1B2B3B4B5D1L1",
|
||||||
NavigationEquipment: "NAV/ABAS",
|
NavigationEquipment: "NAV/ABAS",
|
||||||
|
|||||||
+122
-64
@@ -3,6 +3,7 @@ package parsers
|
|||||||
import (
|
import (
|
||||||
"caatsm/internal/config"
|
"caatsm/internal/config"
|
||||||
"caatsm/internal/domain"
|
"caatsm/internal/domain"
|
||||||
|
"caatsm/pkg/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -16,65 +17,32 @@ var (
|
|||||||
emptyLineRemove = regexp.MustCompile(`(?m)^\s*$`)
|
emptyLineRemove = regexp.MustCompile(`(?m)^\s*$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AFTNParser is responsible for parsing AFTN messages.
|
||||||
type AFTNParser struct {
|
type AFTNParser struct {
|
||||||
BodyPattern *config.BodyConfig
|
bodyPattern map[string]config.BodyConfig // Injected configuration for body patterns.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses a generic AFTN message based on its type.
|
// NewAFTNParser creates a new instance of AFTNParser.
|
||||||
func (p AFTNParser) Parse(text string) (interface{}, error) {
|
func NewAFTNParser(myPatterns map[string]config.BodyConfig) *AFTNParser {
|
||||||
data := ParseBody(text)
|
return &AFTNParser{bodyPattern: myPatterns}
|
||||||
|
|
||||||
switch data["type"] {
|
|
||||||
case "ARR":
|
|
||||||
return &domain.ARR{
|
|
||||||
Category: data["type"],
|
|
||||||
AircraftID: data["number"],
|
|
||||||
SSRModeAndCode: data["ssr"],
|
|
||||||
DepartureAirport: data["departure"],
|
|
||||||
ArrivalAirport: data["arrival"],
|
|
||||||
}, nil
|
|
||||||
case "DEP":
|
|
||||||
return &domain.DEP{
|
|
||||||
AircraftID: data["number"],
|
|
||||||
SSRModeAndCode: data["ssr"],
|
|
||||||
DepartureAirport: data["departure"],
|
|
||||||
DepartureTime: data["departure_time"],
|
|
||||||
Destination: data["arrival"],
|
|
||||||
}, nil
|
|
||||||
case "FPL":
|
|
||||||
return &domain.FPL{
|
|
||||||
Category: data["type"],
|
|
||||||
FlightNumber: data["number"],
|
|
||||||
FlightRulesAndType: data["indicator"],
|
|
||||||
AircraftID: data["aircraft"],
|
|
||||||
SSRModeAndCode: data["surve"],
|
|
||||||
DepartureAirport: data["departure"],
|
|
||||||
DepartureTime: data["departure_time"],
|
|
||||||
CruisingSpeedAndLevel: data["speed"] + data["level"],
|
|
||||||
Route: data["route"],
|
|
||||||
DestinationAndTotalTime: data["destination"] + data["estt"],
|
|
||||||
AlternateAirport: data["alter"],
|
|
||||||
OtherInfo: data["pbn"] + " " + data["nav"] + " " + "REG/" + data["reg"] + " " + "EET/" + data["eet"] + " " + "SEL/" + data["sel"] + " " + "PER/" + data["performance"] + " " + "RIF/" + data["rif"],
|
|
||||||
SupplementaryInfo: "RMK/" + data["remark"],
|
|
||||||
}, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid message type")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeEmptyLines removes empty lines from a given text.
|
// DefaultParser creates a new instance of AFTNParser with default patterns.
|
||||||
func removeEmptyLines(text string) string {
|
func DefaultParser() *AFTNParser {
|
||||||
cleanedText := emptyLineRemove.ReplaceAllString(text, "")
|
return &AFTNParser{bodyPattern: config.GetBodyPatterns()}
|
||||||
return strings.ReplaceAll(cleanedText, "\n\n", "\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAFTN parses an AFTN message from raw text.
|
func (p *AFTNParser) GetBodyPatterns() map[string]config.BodyConfig {
|
||||||
func ParseAFTN(rawMessage string) (*domain.AFTN, error) {
|
return p.bodyPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse is the main method to parse an AFTN message.
|
||||||
|
func (p *AFTNParser) Parse(rawMessage string) (*domain.AFTN, error) {
|
||||||
cleanedText := removeEmptyLines(rawMessage)
|
cleanedText := removeEmptyLines(rawMessage)
|
||||||
lines := strings.Split(cleanedText, "\n")
|
lines := strings.Split(cleanedText, "\n")
|
||||||
|
|
||||||
if len(lines) < 4 {
|
if len(lines) < 4 {
|
||||||
return nil, fmt.Errorf("invalid AFTN message format")
|
return nil, fmt.Errorf("invalid AFTN message format: insufficient lines")
|
||||||
}
|
}
|
||||||
|
|
||||||
header, err := parseHeader(lines[0])
|
header, err := parseHeader(lines[0])
|
||||||
@@ -92,12 +60,17 @@ func ParseAFTN(rawMessage string) (*domain.AFTN, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
text, bodyType, err := parseText(strings.Join(lines[3:], "\n"))
|
text, bodyType, err := parseTextInfo(strings.Join(lines[3:], "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyData, err := parseBodyData(text)
|
bodyData, err := p.extractBodyData(text)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
aftn, err := p.createAFTN(bodyData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -108,7 +81,7 @@ func ParseAFTN(rawMessage string) (*domain.AFTN, error) {
|
|||||||
TimeAndReceiver: timeAndReceiver,
|
TimeAndReceiver: timeAndReceiver,
|
||||||
Text: text,
|
Text: text,
|
||||||
Category: bodyType,
|
Category: bodyType,
|
||||||
BodyData: bodyData,
|
BodyData: aftn,
|
||||||
ReceivedTime: time.Now(),
|
ReceivedTime: time.Now(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -117,7 +90,7 @@ func ParseAFTN(rawMessage string) (*domain.AFTN, error) {
|
|||||||
func parseHeader(line string) (domain.Header, error) {
|
func parseHeader(line string) (domain.Header, error) {
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
if len(parts) < 3 {
|
if len(parts) < 3 {
|
||||||
return domain.Header{}, fmt.Errorf("invalid header format")
|
return domain.Header{}, fmt.Errorf("invalid header format: %s", line)
|
||||||
}
|
}
|
||||||
return domain.Header{
|
return domain.Header{
|
||||||
StartSignal: parts[0],
|
StartSignal: parts[0],
|
||||||
@@ -130,7 +103,7 @@ func parseHeader(line string) (domain.Header, error) {
|
|||||||
func parsePriorityAndSender(line string) (domain.PriorityAndSender, error) {
|
func parsePriorityAndSender(line string) (domain.PriorityAndSender, error) {
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
return domain.PriorityAndSender{}, fmt.Errorf("invalid priority and sender format")
|
return domain.PriorityAndSender{}, fmt.Errorf("invalid priority and sender format: %s", line)
|
||||||
}
|
}
|
||||||
return domain.PriorityAndSender{
|
return domain.PriorityAndSender{
|
||||||
Priority: parts[0],
|
Priority: parts[0],
|
||||||
@@ -142,7 +115,7 @@ func parsePriorityAndSender(line string) (domain.PriorityAndSender, error) {
|
|||||||
func parseTimeAndReceiver(line string) (domain.TimeAndReceiver, error) {
|
func parseTimeAndReceiver(line string) (domain.TimeAndReceiver, error) {
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
return domain.TimeAndReceiver{}, fmt.Errorf("invalid time and receiver format")
|
return domain.TimeAndReceiver{}, fmt.Errorf("invalid time and receiver format: %s", line)
|
||||||
}
|
}
|
||||||
return domain.TimeAndReceiver{
|
return domain.TimeAndReceiver{
|
||||||
Time: parts[0],
|
Time: parts[0],
|
||||||
@@ -150,23 +123,108 @@ func parseTimeAndReceiver(line string) (domain.TimeAndReceiver, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseText parses the text and extracts the body type from an AFTN message.
|
// parseTextInfo parses the text and extracts the body type from an AFTN message.
|
||||||
func parseText(text string) (string, string, error) {
|
func parseTextInfo(text string) (string, string, error) {
|
||||||
match := textPattern.FindStringSubmatch(text)
|
match := textPattern.FindStringSubmatch(text)
|
||||||
if len(match) > 1 {
|
if len(match) > 1 {
|
||||||
return match[0], match[1], nil
|
return match[0], match[1], nil
|
||||||
}
|
}
|
||||||
return "", "", fmt.Errorf("invalid text format")
|
return "", "", fmt.Errorf("invalid text format: %s", text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseBodyData parses the body data of an AFTN message.
|
func (p *AFTNParser) ParseBody(body string) (interface{}, error) {
|
||||||
func parseBodyData(text string) (interface{}, error) {
|
bodyData, err := p.extractBodyData(body)
|
||||||
bodyParser := AFTNParser{}
|
|
||||||
bodyData, err := bodyParser.Parse(text)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse body data: %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
return bodyData, nil
|
|
||||||
|
aftn, err := p.createAFTN(bodyData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aftn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseBody parses the body data of an AFTN message.
|
||||||
|
func (p *AFTNParser) createAFTN(data map[string]string) (interface{}, error) {
|
||||||
|
switch data["type"] {
|
||||||
|
case "ARR":
|
||||||
|
return &domain.ARR{
|
||||||
|
Category: data["type"],
|
||||||
|
AircraftID: data["number"],
|
||||||
|
SSRModeAndCode: data["ssr"],
|
||||||
|
DepartureAirport: data["departure"],
|
||||||
|
ArrivalAirport: data["arrival"],
|
||||||
|
}, nil
|
||||||
|
case "DEP":
|
||||||
|
return &domain.DEP{
|
||||||
|
Category: data["type"],
|
||||||
|
AircraftID: data["number"],
|
||||||
|
SSRModeAndCode: data["ssr"],
|
||||||
|
DepartureAirport: data["departure"],
|
||||||
|
DepartureTime: data["departure_time"],
|
||||||
|
Destination: data["arrival"],
|
||||||
|
}, nil
|
||||||
|
case "FPL":
|
||||||
|
return &domain.FPL{
|
||||||
|
Category: data["type"],
|
||||||
|
FlightNumber: data["number"],
|
||||||
|
ReferenceData: data["reference_data"],
|
||||||
|
AircraftID: data["aircraft"],
|
||||||
|
SSRModeAndCode: data["surve"],
|
||||||
|
FlightRulesAndType: data["indicator"],
|
||||||
|
CruisingSpeedAndLevel: data["speed"] + data["level"],
|
||||||
|
DepartureAirport: data["departure"],
|
||||||
|
DepartureTime: data["departure_time"],
|
||||||
|
Route: data["route"],
|
||||||
|
DestinationAndTotalTime: data["destination"] + data["estt"],
|
||||||
|
AlternateAirport: data["alter"],
|
||||||
|
OtherInfo: fmt.Sprintf("%s %s REG/%s EET/%s SEL/%s PER/%s RIF/%s",
|
||||||
|
data["pbn"], data["nav"], data["reg"], data["eet"], data["sel"], data["performance"], data["rif"]),
|
||||||
|
SupplementaryInfo: "RMK/" + data["remark"],
|
||||||
|
EstimatedArrivalTime: data["estimated_arrival_time"],
|
||||||
|
PBN: data["pbn"],
|
||||||
|
NavigationEquipment: data["nav"],
|
||||||
|
EstimatedElapsedTime: data["eet"],
|
||||||
|
SELCALCode: data["sel"],
|
||||||
|
PerformanceCategory: data["performance"],
|
||||||
|
RerouteInformation: data["rif"],
|
||||||
|
Remarks: data["remark"],
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid message type: %s", data["type"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractBodyData extracts the body data from an AFTN message.
|
||||||
|
func (p *AFTNParser) extractBodyData(text string) (map[string]string, error) {
|
||||||
|
log := utils.Logger
|
||||||
|
data := make(map[string]string)
|
||||||
|
for _, pattern := range p.GetBodyPatterns() {
|
||||||
|
for i, p := range pattern.Patterns {
|
||||||
|
log.Debugf("Trying pattern %d: %s\n %s\n", i, p.Comments, p.Pattern)
|
||||||
|
re := p.Expression
|
||||||
|
match := re.FindStringSubmatch(text)
|
||||||
|
if match != nil {
|
||||||
|
log.Debugf("Matched : %v \n", match)
|
||||||
|
for i, name := range re.SubexpNames() {
|
||||||
|
if i != 0 && name != "" {
|
||||||
|
data[name] = match[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
log.Debugf("No match for pattern %d\n", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Errorf("No matching pattern found for text: %s", text)
|
||||||
|
return nil, fmt.Errorf("no matching pattern found for text: %s", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeEmptyLines removes empty lines from a given text.
|
||||||
|
func removeEmptyLines(text string) string {
|
||||||
|
return emptyLineRemove.ReplaceAllString(text, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAFTN validates the fields of an AFTN message.
|
// ValidateAFTN validates the fields of an AFTN message.
|
||||||
@@ -176,7 +234,7 @@ func ValidateAFTN(msg *domain.AFTN) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !validPriority.MatchString(msg.PriorityAndSender.Priority) {
|
if !validPriority.MatchString(msg.PriorityAndSender.Priority) {
|
||||||
return fmt.Errorf("invalid priority code")
|
return fmt.Errorf("invalid priority code: %s", msg.PriorityAndSender.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validAddress.MatchString(msg.TimeAndReceiver.Receiver) || !validAddress.MatchString(msg.PriorityAndSender.Sender) {
|
if !validAddress.MatchString(msg.TimeAndReceiver.Receiver) || !validAddress.MatchString(msg.PriorityAndSender.Sender) {
|
||||||
|
|||||||
@@ -2,20 +2,32 @@ package parsers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"caatsm/internal/domain"
|
"caatsm/internal/domain"
|
||||||
|
"testing"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAFTNParser(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "AFTNParser Suite")
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("AFTN Parser", func() {
|
var _ = Describe("AFTN Parser", func() {
|
||||||
Describe("Parse", func() {
|
Describe("Parse", func() {
|
||||||
|
var parser *AFTNParser
|
||||||
|
BeforeEach(func() {
|
||||||
|
parser = DefaultParser()
|
||||||
|
})
|
||||||
|
|
||||||
It("should parse ARR messages correctly", func() {
|
It("should parse ARR messages correctly", func() {
|
||||||
message := "(ARR-AB123-SSR1234-KJFK-KLAX)"
|
message := "(ARR-AB123-SSR1234-KJFK-KLAX)"
|
||||||
parser := AFTNParser{}
|
// parser := DefaultParser()
|
||||||
parsedMessage, err := parser.Parse(message)
|
parsedMessage, err := parser.ParseBody(message)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.ARR{}))
|
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.ARR{}))
|
||||||
arrMessage := parsedMessage.(*domain.ARR)
|
arrMessage := parsedMessage.(*domain.ARR)
|
||||||
|
|
||||||
Expect(arrMessage.Category).To(Equal("ARR"))
|
Expect(arrMessage.Category).To(Equal("ARR"))
|
||||||
Expect(arrMessage.AircraftID).To(Equal("AB123"))
|
Expect(arrMessage.AircraftID).To(Equal("AB123"))
|
||||||
Expect(arrMessage.SSRModeAndCode).To(Equal("SSR1234"))
|
Expect(arrMessage.SSRModeAndCode).To(Equal("SSR1234"))
|
||||||
@@ -25,11 +37,11 @@ var _ = Describe("AFTN Parser", func() {
|
|||||||
|
|
||||||
It("should parse DEP messages correctly", func() {
|
It("should parse DEP messages correctly", func() {
|
||||||
message := "(DEP-AB123-SSR1234-KJFK-1500-KLAX)"
|
message := "(DEP-AB123-SSR1234-KJFK-1500-KLAX)"
|
||||||
parser := AFTNParser{}
|
parsedMessage, err := parser.ParseBody(message)
|
||||||
parsedMessage, err := parser.Parse(message)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.DEP{}))
|
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.DEP{}))
|
||||||
depMessage := parsedMessage.(*domain.DEP)
|
depMessage := parsedMessage.(*domain.DEP)
|
||||||
|
Expect(depMessage.Category).To(Equal("DEP"))
|
||||||
Expect(depMessage.AircraftID).To(Equal("AB123"))
|
Expect(depMessage.AircraftID).To(Equal("AB123"))
|
||||||
Expect(depMessage.SSRModeAndCode).To(Equal("SSR1234"))
|
Expect(depMessage.SSRModeAndCode).To(Equal("SSR1234"))
|
||||||
Expect(depMessage.DepartureAirport).To(Equal("KJFK"))
|
Expect(depMessage.DepartureAirport).To(Equal("KJFK"))
|
||||||
@@ -45,8 +57,7 @@ var _ = Describe("AFTN Parser", func() {
|
|||||||
-K0859S1040 PIAKS G330 PIMOL A539 BTO W82 DOGAR
|
-K0859S1040 PIAKS G330 PIMOL A539 BTO W82 DOGAR
|
||||||
-ZBAA0153 ZBYN
|
-ZBAA0153 ZBYN
|
||||||
-PBN/A1B2B3B4B5D1L1 NAV/ABAS REG/B6513 EET/ZBPE0112 SEL/KMAL PER/C RIF/FRT N640 ZBYN RMK/TCAS EQUIPPED)`
|
-PBN/A1B2B3B4B5D1L1 NAV/ABAS REG/B6513 EET/ZBPE0112 SEL/KMAL PER/C RIF/FRT N640 ZBYN RMK/TCAS EQUIPPED)`
|
||||||
parser := AFTNParser{}
|
parsedMessage, err := parser.ParseBody(message)
|
||||||
parsedMessage, err := parser.Parse(message)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.FPL{}))
|
Expect(parsedMessage).To(BeAssignableToTypeOf(&domain.FPL{}))
|
||||||
fplMessage := parsedMessage.(*domain.FPL)
|
fplMessage := parsedMessage.(*domain.FPL)
|
||||||
@@ -60,28 +71,32 @@ var _ = Describe("AFTN Parser", func() {
|
|||||||
Expect(fplMessage.Route).To(Equal("PIAKS G330 PIMOL A539 BTO W82 DOGAR"))
|
Expect(fplMessage.Route).To(Equal("PIAKS G330 PIMOL A539 BTO W82 DOGAR"))
|
||||||
Expect(fplMessage.DestinationAndTotalTime).To(Equal("ZBAA0153"))
|
Expect(fplMessage.DestinationAndTotalTime).To(Equal("ZBAA0153"))
|
||||||
Expect(fplMessage.AlternateAirport).To(Equal("ZBYN"))
|
Expect(fplMessage.AlternateAirport).To(Equal("ZBYN"))
|
||||||
|
// fmt.Println(fplMessage.OtherInfo)
|
||||||
Expect(fplMessage.OtherInfo).To(Equal("PBN/A1B2B3B4B5D1L1 NAV/ABAS REG/B6513 EET/ZBPE0112 SEL/KMAL PER/C RIF/FRT N640 ZBYN"))
|
Expect(fplMessage.OtherInfo).To(Equal("PBN/A1B2B3B4B5D1L1 NAV/ABAS REG/B6513 EET/ZBPE0112 SEL/KMAL PER/C RIF/FRT N640 ZBYN"))
|
||||||
Expect(fplMessage.SupplementaryInfo).To(Equal("RMK/TCAS EQUIPPED"))
|
Expect(fplMessage.SupplementaryInfo).To(Equal("RMK/TCAS EQUIPPED"))
|
||||||
|
Expect(fplMessage.PBN).To(Equal("PBN/A1B2B3B4B5D1L1"))
|
||||||
|
// fmt.Println(fplMessage.EstimatedElapsedTime)
|
||||||
|
Expect(fplMessage.EstimatedElapsedTime).To(Equal("ZBPE0112"))
|
||||||
|
Expect(fplMessage.SELCALCode).To(Equal("KMAL"))
|
||||||
|
Expect(fplMessage.PerformanceCategory).To(Equal("C"))
|
||||||
|
Expect(fplMessage.RerouteInformation).To(Equal("FRT N640 ZBYN"))
|
||||||
|
Expect(fplMessage.Remarks).To(Equal("TCAS EQUIPPED"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should return an error for invalid message types", func() {
|
It("should return an error for invalid message types", func() {
|
||||||
message := "(XYZ-AB123-SSR1234-KJFK-KLAX)"
|
message := "(XYZ-AB123-SSR1234-KJFK-KLAX)"
|
||||||
parser := AFTNParser{}
|
_, err := parser.ParseBody(message)
|
||||||
_, err := parser.Parse(message)
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(Equal("invalid message type"))
|
Expect(err.Error()).To(Equal("invalid message type: XYZ"))
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
Describe("ParseAFTN", func() {
|
|
||||||
It("should parse a valid AFTN message", func() {
|
It("should parse a valid AFTN message", func() {
|
||||||
rawMessage := `ZCZC TMQ2611 151524
|
rawMessage := `ZCZC TMQ2611 151524
|
||||||
FF SENDERAA
|
FF SENDERAA
|
||||||
151524 RECEIVERAA
|
151524 RECEIVERAA
|
||||||
(ARR-AB123-SSR1234-KJFK-KLAX)`
|
(ARR-AB123-SSR1234-KJFK-KLAX)`
|
||||||
|
|
||||||
aftnMessage, err := ParseAFTN(rawMessage)
|
aftnMessage, err := parser.Parse(rawMessage)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(aftnMessage).NotTo(BeNil())
|
Expect(aftnMessage).NotTo(BeNil())
|
||||||
Expect(aftnMessage.Header.StartSignal).To(Equal("ZCZC"))
|
Expect(aftnMessage.Header.StartSignal).To(Equal("ZCZC"))
|
||||||
@@ -95,9 +110,9 @@ FF SENDERAA
|
|||||||
TMQ2611
|
TMQ2611
|
||||||
151524`
|
151524`
|
||||||
|
|
||||||
_, err := ParseAFTN(rawMessage)
|
_, err := parser.Parse(rawMessage)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(Equal("invalid AFTN message format"))
|
Expect(err.Error()).To(Equal("invalid AFTN message format: insufficient lines"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -164,7 +179,7 @@ TMQ2611
|
|||||||
}
|
}
|
||||||
err := ValidateAFTN(aftnMessage)
|
err := ValidateAFTN(aftnMessage)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(Equal("invalid priority code"))
|
Expect(err.Error()).To(Equal("invalid priority code: ZZ"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should return an error for invalid address format", func() {
|
It("should return an error for invalid address format", func() {
|
||||||
|
|||||||
Reference in New Issue
Block a user