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

Error handling #73

Open
wants to merge 68 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
08adbda
Add Todo and Journal Property Methods
spslater Apr 1, 2023
14095cc
Add Alarm, Timezone, and FreeBusy Property Methods
spslater Apr 2, 2023
67727dd
Fix Typos in a couple places
spslater Apr 6, 2023
b51e64d
Merge branch 'arran4:master' into add-todo-journal
spslater Apr 6, 2023
6d4f14f
Add Comment and Category Properties to Components
spslater Apr 27, 2023
a5a215d
Merge branch 'master' into add-todo-journal
spslater Apr 27, 2023
4b2d6a1
Add changes for All Day Events to All Day Todos
spslater Apr 28, 2023
23c4714
added errors.go and converted errors to constants for better error ha…
ManoloTonto1 Jul 12, 2023
b69874f
fixed some namings
ManoloTonto1 Jul 12, 2023
7d97e96
Bump gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0
dependabot[bot] Sep 6, 2023
ce8cff1
Merge pull request #76 from arran4/dependabot/go_modules/gopkg.in/yam…
arran4 Sep 6, 2023
0abebc2
Add VEvent.GetDtStampTime
galenwarren Nov 8, 2023
acf49e9
Merge pull request #80 from coachclientconnect/add-get-timestamp
arran4 Nov 11, 2023
a0f11e3
add possibility to remove VEvent from calendar by id
zachmann Nov 23, 2023
70f69c8
undo formatting change
zachmann Nov 23, 2023
1dfe73f
remove redundant return statement
zachmann Nov 24, 2023
7678c37
Merge pull request #81 from zachmann/master
arran4 Nov 24, 2023
e69ce9c
Add ComponentPropertyPriority; the VTODO component can have that
quite Dec 4, 2023
aef0a29
Merge pull request #82 from quite/add-component-priority
arran4 Dec 7, 2023
8525f6b
Add {Get,Set}LastModifiedAt
bcspragu Dec 18, 2023
1a61754
Merge pull request #83 from bcspragu/last-modified
arran4 Dec 20, 2023
a55aac2
Merge remote-tracking branch 'origin/pull-66-add-todo-journal-orphan'…
arran4 Jan 8, 2024
5f3bef9
Unnecessary functions causing lint recursion errors.
arran4 Jan 8, 2024
55df13e
Consistent todo receiver
arran4 Jan 8, 2024
9e30bdf
Ignore explicitly
arran4 Jan 8, 2024
1e96c15
Consistent receivers.
arran4 Jan 8, 2024
cf8d1b3
Ignore explicitly
arran4 Jan 8, 2024
804f4d3
Merge pull request #84 from arran4/pull-66-add-todo-journal
arran4 Jan 8, 2024
681cc6e
fix panic for missing property param operator
brackendawson Jan 27, 2024
3631125
fix panic when property ends without colon or value
brackendawson Jan 27, 2024
a8f0586
fix panic when param value has incomplete escape sequence
brackendawson Jan 27, 2024
46e2a5c
Exclude fuzz testing from pre-1.18 toolchains
brackendawson Jan 28, 2024
51fa6f1
Merge pull request #85 from brackendawson/panic
arran4 Jan 28, 2024
3ffa099
fix: only escape property values when serializing.
frereit Feb 9, 2024
0f8a325
fix: reorder string replaces in escaping values.
frereit Feb 9, 2024
647cf9e
test: Add test for escaped semicolons in property parameters
frereit Feb 13, 2024
542d6e5
Merge pull request #86 from JM-Lemmi/fix/text_escaping
arran4 Feb 14, 2024
7bd8708
test: Add test for escaped semicolons in RRULEs
frereit Feb 15, 2024
bb39d64
Revert "fix: only escape property values when serializing."
frereit Feb 15, 2024
0fcebed
Merge pull request #87 from JM-Lemmi/fix/text_escaping
arran4 Feb 15, 2024
f5b4408
Prefix mailto: for email in organizer property
meain Feb 27, 2024
93ca35f
Only conditionally add in the mailto: prefix for attendee and organizer
meain Mar 4, 2024
84a339a
Merge pull request #88 from meain/org-mailto
arran4 Mar 4, 2024
02c6335
Re-add Calendar.RemoveEvent method
zachmann Apr 11, 2024
9fab3f0
Merge pull request #90 from zachmann/master
arran4 Apr 11, 2024
1e5b6e4
add: contributing.md
brenank May 21, 2024
27bb2dd
fix: simplify & update ghas
brenank May 21, 2024
909bd3b
fix: explicitly list golang versions
brenank May 21, 2024
3e4aba3
fix: use macos-13, arm is not supported by setup-go
brenank May 21, 2024
f044c04
Merge pull request #92 from brenank/brenank/update-golang
arran4 May 21, 2024
008589d
add: stable serialization of property parameters
brenank May 20, 2024
baa1c1d
add: serialiation test
brenank May 20, 2024
ea37e62
fix: VFREEBUSY serialization
brenank May 20, 2024
8d1cec9
breaking: unescape Property.Value of type TEXT
brenank May 19, 2024
68b453c
refactor: fix linting errors
brenank May 21, 2024
b866620
refactor: reduce scope of gitignore
brenank May 30, 2024
2f726f2
refactor: switch syntax
brenank May 30, 2024
9a99514
fix: add test err assertion
brenank May 30, 2024
20061ba
fix: reduce build restriction on serialization test
brenank May 30, 2024
6591742
Merge pull request #91 from brenank/master
arran4 May 30, 2024
c331f7a
Add ComponentPropertyRelatedTo; the VTODO component can have that
quite Jul 10, 2024
ea4ce01
Merge pull request #94 from quite/add-component-relatedto
arran4 Jul 10, 2024
f76e1f3
fixed merge conflicts
ManoloTonto1 Sep 25, 2024
e616cd6
fixed some namings
ManoloTonto1 Jul 12, 2023
2520cb0
Merge branch 'master' of github.com:ManoloTonto1/golang-ical
ManoloTonto1 Sep 25, 2024
4c3688b
fixed som functions that are using the wrong Struct Embeddings
ManoloTonto1 Sep 25, 2024
1d9da2e
Some suggestions, this could be improved still. (#1)
arran4 Oct 4, 2024
3a306dd
Error handling conflicts again (#2)
arran4 Oct 21, 2024
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
18 changes: 9 additions & 9 deletions calendar.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,10 @@ func ParseCalendar(r io.Reader) (*Calendar, error) {
}
line, err := ParseProperty(*l)
if err != nil {
return nil, fmt.Errorf("parsing line %d: %w", ln, err)
return nil, fmt.Errorf("%s %d: %w", ParsingLineError, ln, err)
}
if line == nil {
return nil, fmt.Errorf("parsing calendar line %d", ln)
return nil, fmt.Errorf("%s %d", ParsingCalendarLineError, ln)
}
switch state {
case "begin":
Expand All @@ -469,10 +469,10 @@ func ParseCalendar(r io.Reader) (*Calendar, error) {
case "VCALENDAR":
state = "properties"
default:
return nil, errors.New("malformed calendar; expected a vcalendar")
return nil, errors.New(MalformedCalendarExpectedVCalendarError)
}
default:
return nil, errors.New("malformed calendar; expected begin")
return nil, errors.New(MalformedCalendarExpectedBeginError)
}
case "properties":
switch line.IANAToken {
Expand All @@ -481,7 +481,7 @@ func ParseCalendar(r io.Reader) (*Calendar, error) {
case "VCALENDAR":
state = "end"
default:
return nil, errors.New("malformed calendar; expected end")
return nil, errors.New(MalformedCalendarExpectedEndError)
}
case "BEGIN":
state = "components"
Expand All @@ -499,7 +499,7 @@ func ParseCalendar(r io.Reader) (*Calendar, error) {
case "VCALENDAR":
state = "end"
default:
return nil, errors.New("malformed calendar; expected end")
return nil, errors.New(MalformedCalendarExpectedEndError)
}
case "BEGIN":
co, err := GeneralParseComponent(cs, line)
Expand All @@ -510,12 +510,12 @@ func ParseCalendar(r io.Reader) (*Calendar, error) {
c.Components = append(c.Components, co)
}
default:
return nil, errors.New("malformed calendar; expected begin or end")
return nil, errors.New(MalformedCalendarExpectedBeginOrEndError)
}
case "end":
return nil, errors.New("malformed calendar; unexpected end")
return nil, errors.New(MalformedCalendarUnexpectedEndError)
default:
return nil, errors.New("malformed calendar; bad state")
return nil, errors.New(MalformedCalendarBadStateError)
}
}
return c, nil
Expand Down
22 changes: 11 additions & 11 deletions components.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,19 +156,19 @@ func (event *VEvent) SetDuration(d time.Duration) error {
return nil
}
}
return errors.New("start or end not yet defined")
return errors.New(StartOrEndNotYetDefinedError)
}

func (event *VEvent) getTimeProp(componentProperty ComponentProperty, expectAllDay bool) (time.Time, error) {
timeProp := event.GetProperty(componentProperty)
if timeProp == nil {
return time.Time{}, errors.New("property not found")
return time.Time{}, errors.New(PropertyNotFoundError)
}

timeVal := timeProp.BaseProperty.Value
matched := timeStampVariations.FindStringSubmatch(timeVal)
if matched == nil {
return time.Time{}, fmt.Errorf("time value not matched, got '%s'", timeVal)
return time.Time{}, fmt.Errorf("%s, got '%s'", TimeValueNotMatchedError, timeVal)
}
tOrZGrp := matched[2]
zGrp := matched[4]
Expand All @@ -179,7 +179,7 @@ func (event *VEvent) getTimeProp(componentProperty ComponentProperty, expectAllD
var propLoc *time.Location
if tzIdOk {
if len(tzId) != 1 {
return time.Time{}, errors.New("expected only one TZID")
return time.Time{}, errors.New(ExpectedOneTZIDError)
}
var tzErr error
propLoc, tzErr = time.LoadLocation(tzId[0])
Expand All @@ -202,7 +202,7 @@ func (event *VEvent) getTimeProp(componentProperty ComponentProperty, expectAllD
}
}

return time.Time{}, fmt.Errorf("time value matched but unsupported all-day timestamp, got '%s'", timeVal)
return time.Time{}, fmt.Errorf("%s, got '%s'", TimeValueMatchedButUnsupportedAllDayTimeStampError, timeVal)
}

if grp1len > 0 && grp3len > 0 && tOrZGrp == "T" && zGrp == "Z" {
Expand All @@ -223,7 +223,7 @@ func (event *VEvent) getTimeProp(componentProperty ComponentProperty, expectAllD
}
}

return time.Time{}, fmt.Errorf("time value matched but not supported, got '%s'", timeVal)
return time.Time{}, fmt.Errorf("%s, got '%s'", TimeValueMatchedButNotSupportedError, timeVal)
}

func (event *VEvent) GetStartAt() (time.Time, error) {
Expand Down Expand Up @@ -519,7 +519,7 @@ func GeneralParseComponent(cs *CalendarStream, startLine *BaseProperty) (Compone
var co Component
switch startLine.Value {
case "VCALENDAR":
return nil, errors.New("malformed calendar; vcalendar not where expected")
return nil, errors.New(MalformedCalendarVCalendarNotWhereExpectedError)
case "VEVENT":
co = ParseVEvent(cs, startLine)
case "VTODO":
Expand Down Expand Up @@ -660,18 +660,18 @@ func ParseComponent(cs *CalendarStream, startLine *BaseProperty) (ComponentBase,
}
line, err := ParseProperty(*l)
if err != nil {
return cb, fmt.Errorf("parsing component property %d: %w", ln, err)
return cb, fmt.Errorf("%s %d: %w", ParsingComponentPropertyError, ln, err)
}
if line == nil {
return cb, errors.New("parsing component line")
return cb, errors.New(ParsingComponentLineError)
}
switch line.IANAToken {
case "END":
switch line.Value {
case startLine.Value:
return cb, nil
default:
return cb, errors.New("unbalanced end")
return cb, errors.New(UnbalancedEndError)
}
case "BEGIN":
co, err := GeneralParseComponent(cs, line)
Expand All @@ -685,5 +685,5 @@ func ParseComponent(cs *CalendarStream, startLine *BaseProperty) (ComponentBase,
cb.Properties = append(cb.Properties, IANAProperty{*line})
}
}
return cb, errors.New("ran out of lines")
return cb, errors.New(OutOfLinesError)
}
35 changes: 35 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ics

const (
MalformedCalendarExpectedVCalendarError = "malformed calendar; expected a vcalendar"
MalformedCalendarExpectedBeginError = "malformed calendar; expected begin"
MalformedCalendarExpectedEndError = "malformed calendar; expected a end"
MalformedCalendarExpectedBeginOrEndError = "malformed calendar; expected begin or end"

MalformedCalendarUnexpectedEndError = "malformed calendar; unexpected end"
MalformedCalendarBadStateError = "malformed calendar; bad state"
MalformedCalendarVCalendarNotWhereExpectedError = "malformed calendar; vcalendar not where expected"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case and others I think there there are too many errors. I would prefer to see something like:

ErrorMalformedCalendar = errors.New("malformed calendar")

Then it be embellished with detail when it is returned like @arran4 suggested in #98:

return nil, fmt.Errorf("%w: expected begin or end", ErrorMalformedCalendar)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not bothered by the quantity, but I do think regardless, it should be wrapped in a ErrorMalformedCalendar that is a good suggestion either direction.

I have some things to do I will have to get back to this.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also not a blocker.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quantity has practical concerns for me: Say I'm writing a server and choosing a HTTP status code. If the user uploaded an invalid calendar I want to return 400. If something else happened, such as the connection dropped and the io.Reader returned an EOF, then I want to return 500. I now have to check if the error was any one of the many parse errors and hope that this module doesn't make any new ones. I'm happy to drop this thread but want to point out that once you ship all theses errors, you can't take it back without a breaking change.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is possible using error.Is sorry I didn't ignore this concern I just failed to follow up on it. I am happy to work through a simple example if you like?


StartOrEndNotYetDefinedError = "start or end not yet defined"
PropertyNotFoundError = "property not found"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to be reliably compared these should be errors rather than strings.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(But technically not a blocker.)

ExpectedOneTZIDError = "expected one TZID"

TimeValueNotMatchedError = "time value not matched"
TimeValueMatchedButUnsupportedAllDayTimeStampError = "time value matched but unsupported all-day timestamp"
TimeValueMatchedButNotSupportedError = "time value matched but not supported"

ParsingComponentPropertyError = "parsing component property"
ParsingComponentLineError = "parsing component line"
ParsingLineError = "parsing line"
ParsingCalendarLineError = "parsing calendar line"
ParsingPropertyError = "parsing property"
ParseError = "parse error"

MissingPropertyValueError = "missing property value"

UnexpectedASCIICharError = "unexpected char ascii"
UnexpectedDoubleQuoteInPropertyParamValueError = "unexpected double quote in property param value"

UnbalancedEndError = "unbalanced end"
OutOfLinesError = "ran out of lines"
)
13 changes: 7 additions & 6 deletions property.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ics

import (
"bytes"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -174,7 +175,7 @@ func ParseProperty(contentLine ContentLine) (*BaseProperty, error) {
t := r.IANAToken
r, np, err = parsePropertyParam(r, string(contentLine), p+1)
if err != nil {
return nil, fmt.Errorf("parsing property %s: %w", t, err)
return nil, fmt.Errorf("%s %s: %w", ParsingPropertyError, t, err)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't be able to catch ParsingPropertyError error.Is and error.As now support multiple errors, so we can use %w twice, past a certain go version... Since 1.20: https://www.reddit.com/r/golang/comments/z870te/multiple_error_wrapping_is_coming_in_go_120/

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this technical is a bug

}
if r == nil {
return nil, nil
Expand All @@ -198,7 +199,7 @@ func parsePropertyParam(r *BaseProperty, contentLine string, p int) (*BaseProper
case '=':
p += 1
default:
return nil, p, fmt.Errorf("missing property value for %s in %s", k, r.IANAToken)
return nil, p, fmt.Errorf("%s for %s in %s", MissingPropertyValueError, k, r.IANAToken)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the other one. Multiple %w are supported as of 1.20..

I guess that means we should push the go.mod up to that. -- Based on this I'm in support. 1.20 is less than 2 years old. But most stacks are rather current.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this one is just missing a %w wish github had the same feature gitlab does "suggest a fix"

}
for {
if p >= len(contentLine) {
Expand All @@ -207,7 +208,7 @@ func parsePropertyParam(r *BaseProperty, contentLine string, p int) (*BaseProper
var err error
v, p, err = parsePropertyParamValue(contentLine, p)
if err != nil {
return nil, 0, fmt.Errorf("parse error: %w %s in %s", err, k, r.IANAToken)
return nil, 0, fmt.Errorf("%s: %w %s in %s", ParseError, err, k, r.IANAToken)
}
r.ICalParameters[k] = append(r.ICalParameters[k], v)
switch rune(contentLine[p]) {
Expand Down Expand Up @@ -253,10 +254,10 @@ func parsePropertyParamValue(s string, p int) (string, int, error) {
for ; p < len(s) && !done; p++ {
switch s[p] {
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08:
return "", 0, fmt.Errorf("unexpected char ascii:%d in property param value", s[p])
return "", 0, fmt.Errorf("%s:%d in property param value", UnexpectedASCIICharError, s[p])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%w

case 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
0x1C, 0x1D, 0x1E, 0x1F:
return "", 0, fmt.Errorf("unexpected char ascii:%d in property param value", s[p])
return "", 0, fmt.Errorf("%s:%d in property param value", UnexpectedASCIICharError, s[p])
case '\\':
r = append(r, []byte(FromText(string(s[p+1:p+2])))...)
p++
Expand All @@ -276,7 +277,7 @@ func parsePropertyParamValue(s string, p int) (string, int, error) {
done = true
continue
}
return "", 0, fmt.Errorf("unexpected double quote in property param value")
return "", 0, errors.New(UnexpectedDoubleQuoteInPropertyParamValueError)
}
r = append(r, s[p])
}
Expand Down
Loading