From 8c44434c68bac97f6159ff2b2989e278578075b6 Mon Sep 17 00:00:00 2001 From: Igor Shishkin Date: Sat, 21 Dec 2019 22:20:44 +0300 Subject: [PATCH] Add some type safety for film advance mode Signed-off-by: Igor Shishkin --- parser/csv_parser.go | 8 ++- parser/csv_parser_test.go | 37 +++++++------- types/film_advance_mode.go | 64 +++++++++++++++++++++++ types/film_advance_mode_test.go | 90 +++++++++++++++++++++++++++++++++ types/frame.go | 2 +- 5 files changed, 180 insertions(+), 21 deletions(-) create mode 100644 types/film_advance_mode.go create mode 100644 types/film_advance_mode_test.go diff --git a/parser/csv_parser.go b/parser/csv_parser.go index a3591cf..3f2dfaa 100644 --- a/parser/csv_parser.go +++ b/parser/csv_parser.go @@ -416,8 +416,12 @@ func parseShootingMode(s string) (*types.ShootingMode, error) { return types.ShootingModeFromString(*sms) } -func parseFilmAdvanceMode(s string) (*string, error) { - return parseString(s) +func parseFilmAdvanceMode(s string) (*types.FilmAdvanceMode, error) { + fams, err := parseString(s) + if err != nil { + return nil, err + } + return types.FilmAdvanceModeFromString(*fams) } func parseAFMode(s string) (*types.AFMode, error) { diff --git a/parser/csv_parser_test.go b/parser/csv_parser_test.go index 1a97e22..3b9f53c 100644 --- a/parser/csv_parser_test.go +++ b/parser/csv_parser_test.go @@ -51,7 +51,7 @@ func TestTwoFilmsInSingleCSV(t *testing.T) { ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), ExposureCompensation: ptrFloat64(0), FlashCompensation: ptrFloat64(0), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "10/7/2019T20:02:18", tz, types.TimestampFormatUS), MultipleExposure: ptrString("OFF"), @@ -69,7 +69,7 @@ func TestTwoFilmsInSingleCSV(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "10/7/2019T20:02:29", tz, types.TimestampFormatUS), MultipleExposure: ptrString("OFF"), @@ -100,7 +100,7 @@ func TestTwoFilmsInSingleCSV(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeProgramAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "10/13/2019T14:55:38", tz, types.TimestampFormatUS), MultipleExposure: ptrString("OFF"), @@ -120,7 +120,7 @@ func TestTwoFilmsInSingleCSV(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "10/13/2019T14:55:55", tz, types.TimestampFormatUS), MultipleExposure: ptrString("OFF"), @@ -174,7 +174,7 @@ func TestFilmWithPartialTimestampsEUFormatted(t *testing.T) { ExposureCompensation: ptrFloat64(0), FlashCompensation: ptrFloat64(0), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "15/07/2019T20:02:18", tz, types.TimestampFormatEU), MultipleExposure: ptrString("OFF"), @@ -192,7 +192,7 @@ func TestFilmWithPartialTimestampsEUFormatted(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: nil, MultipleExposure: ptrString("OFF"), @@ -422,7 +422,7 @@ func TestPartialData(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), }, { Flag: ptrBool(false), @@ -437,7 +437,7 @@ func TestPartialData(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), }, { @@ -453,7 +453,7 @@ func TestPartialData(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), Timestamp: mustParseTimestamp(t, "07/10/2019T20:02:18", tz, types.TimestampFormatEU), }, @@ -470,7 +470,7 @@ func TestPartialData(t *testing.T) { FlashMode: ptrFlashMode(types.FlashModeOff), MeteringMode: ptrMeteringMode(types.MeteringModeEvaluative), ShootingMode: ptrShootingMode(types.ShootingModeAperturePriorityAE), - FilmAdvanceMode: ptrString("Single-frame"), + FilmAdvanceMode: ptrFilmAdvanceMode(types.FilmAdvanceModeSingleFrame), AFMode: ptrAFMode(types.AFModeOneShotAF), MultipleExposure: ptrString("OFF"), Timestamp: mustParseTimestamp(t, "07/10/2019T20:02:18", tz, types.TimestampFormatEU), @@ -508,11 +508,12 @@ func mustParseTimestamp(t *testing.T, ts string, tz *time.Location, tf string) * return tt } -func ptrInt64(i int64) *int64 { return &i } -func ptrFloat64(f float64) *float64 { return &f } -func ptrString(s string) *string { return &s } -func ptrBool(b bool) *bool { return &b } -func ptrMeteringMode(mm types.MeteringMode) *types.MeteringMode { return &mm } -func ptrShootingMode(sm types.ShootingMode) *types.ShootingMode { return &sm } -func ptrAFMode(am types.AFMode) *types.AFMode { return &am } -func ptrFlashMode(fm types.FlashMode) *types.FlashMode { return &fm } +func ptrInt64(i int64) *int64 { return &i } +func ptrFloat64(f float64) *float64 { return &f } +func ptrString(s string) *string { return &s } +func ptrBool(b bool) *bool { return &b } +func ptrMeteringMode(mm types.MeteringMode) *types.MeteringMode { return &mm } +func ptrShootingMode(sm types.ShootingMode) *types.ShootingMode { return &sm } +func ptrAFMode(am types.AFMode) *types.AFMode { return &am } +func ptrFlashMode(fm types.FlashMode) *types.FlashMode { return &fm } +func ptrFilmAdvanceMode(fam types.FilmAdvanceMode) *types.FilmAdvanceMode { return &fam } diff --git a/types/film_advance_mode.go b/types/film_advance_mode.go new file mode 100644 index 0000000..f9dfa33 --- /dev/null +++ b/types/film_advance_mode.go @@ -0,0 +1,64 @@ +package types + +import ( + "strings" + + "github.com/pkg/errors" +) + +// FilmAdvanceMode ... +type FilmAdvanceMode string + +const ( + // FilmAdvanceModeSingleFrame ... + FilmAdvanceModeSingleFrame FilmAdvanceMode = "Single-frame" + + // FilmAdvanceModeContinuousBodyOnly ... + FilmAdvanceModeContinuousBodyOnly FilmAdvanceMode = "Continuous (body only)" + + // FilmAdvanceModeLowSpeedContinuous ... + FilmAdvanceModeLowSpeedContinuous FilmAdvanceMode = "Low-speed continuous" + + // FilmAdvanceModeHighSpeedContinuous ... + FilmAdvanceModeHighSpeedContinuous FilmAdvanceMode = "High-speed continuous" + + // FilmAdvanceModeUltraHighSpeedContinuous ... + FilmAdvanceModeUltraHighSpeedContinuous FilmAdvanceMode = "Ultra-high-speed continuous" + + // FilmAdvanceMode2secSelfTimer ... + FilmAdvanceMode2secSelfTimer FilmAdvanceMode = "2-sec. self-timer" + + // FilmAdvanceMode10secSelfTimer ... + FilmAdvanceMode10secSelfTimer FilmAdvanceMode = "10-sec. self-timer" +) + +// FilmAdvanceModeFromString ... +func FilmAdvanceModeFromString(s string) (fam *FilmAdvanceMode, err error) { + s = strings.TrimSpace(s) + + var famv FilmAdvanceMode + switch FilmAdvanceMode(s) { + case FilmAdvanceMode10secSelfTimer: + famv = FilmAdvanceMode10secSelfTimer + case FilmAdvanceMode2secSelfTimer: + famv = FilmAdvanceMode2secSelfTimer + case FilmAdvanceModeContinuousBodyOnly: + famv = FilmAdvanceModeContinuousBodyOnly + case FilmAdvanceModeHighSpeedContinuous: + famv = FilmAdvanceModeHighSpeedContinuous + case FilmAdvanceModeLowSpeedContinuous: + famv = FilmAdvanceModeLowSpeedContinuous + case FilmAdvanceModeSingleFrame: + famv = FilmAdvanceModeSingleFrame + case FilmAdvanceModeUltraHighSpeedContinuous: + famv = FilmAdvanceModeUltraHighSpeedContinuous + default: + err = errors.Errorf("error parsing FilmAdvanceMode: unknown value `%s`", s) + } + + return &famv, err +} + +func (famv *FilmAdvanceMode) String() string { + return string(*famv) +} diff --git a/types/film_advance_mode_test.go b/types/film_advance_mode_test.go new file mode 100644 index 0000000..b46a86e --- /dev/null +++ b/types/film_advance_mode_test.go @@ -0,0 +1,90 @@ +package types + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFilmAdvanceMode(t *testing.T) { + r := require.New(t) + + type testCase struct { + name string + input string + expOutput *FilmAdvanceMode + expError error + } + + tcs := []testCase{ + { + name: "Single-frame", + input: "Single-frame", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeSingleFrame), + }, + { + name: "Continuous (body only)", + input: "Continuous (body only)", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeContinuousBodyOnly), + }, + { + name: "Low-speed continuous", + input: "Low-speed continuous", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeLowSpeedContinuous), + }, + { + name: "High-speed continuous", + input: "High-speed continuous", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeHighSpeedContinuous), + }, + { + name: "Ultra-high-speed continuous", + input: "Ultra-high-speed continuous", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeUltraHighSpeedContinuous), + }, + { + name: "2-sec. self-timer", + input: "2-sec. self-timer", + expOutput: ptrFilmAdvanceMode(FilmAdvanceMode2secSelfTimer), + }, + { + name: "10-sec. self-timer", + input: "10-sec. self-timer", + expOutput: ptrFilmAdvanceMode(FilmAdvanceMode10secSelfTimer), + }, + { + name: "Ultra-high-speed continuous with spaces", + input: " Ultra-high-speed continuous ", + expOutput: ptrFilmAdvanceMode(FilmAdvanceModeUltraHighSpeedContinuous), + }, + { + name: "some random text", + input: "aksjdfghq3", + expError: errors.New("error parsing FilmAdvanceMode: unknown value `aksjdfghq3`"), + }, + { + name: "empty string", + input: "", + expError: errors.New("error parsing FilmAdvanceMode: unknown value ``"), + }, + } + + for _, tc := range tcs { + sm, err := FilmAdvanceModeFromString(tc.input) + if tc.expError == nil { + r.Equalf(tc.expOutput, sm, tc.name) + r.NoErrorf(err, tc.name) + } else { + r.Errorf(err, tc.name) + r.Equalf(tc.expError.Error(), err.Error(), tc.name) + } + } +} + +func ptrFilmAdvanceMode(fam FilmAdvanceMode) *FilmAdvanceMode { + if fam == "" { + return nil + } + return &fam +} diff --git a/types/frame.go b/types/frame.go index 2f88d0a..b0762a3 100644 --- a/types/frame.go +++ b/types/frame.go @@ -16,7 +16,7 @@ type Frame struct { FlashMode *FlashMode MeteringMode *MeteringMode ShootingMode *ShootingMode - FilmAdvanceMode *string + FilmAdvanceMode *FilmAdvanceMode AFMode *AFMode BulbExposureTime *string Timestamp *time.Time