diff --git a/go/study/ch02_first_cli_app/calc.go b/go/study/ch02_first_cli_app/calc.go new file mode 100644 index 00000000..a0594804 --- /dev/null +++ b/go/study/ch02_first_cli_app/calc.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + "strconv" +) + +type Calculation interface { + Do(x, y int) Result + Kind() string +} + +type Result interface { + Outcome() string +} + +type Int int + +func (i Int) Outcome() string { + return strconv.Itoa(int(i)) +} + +type Addition struct{} + +func (*Addition) Kind() string { + return "addition" +} + +func (*Addition) Do(x, y int) Result { + return Int(x + y) +} + +type Subtraction struct{} + +func (*Subtraction) Kind() string { + return "subtraction" +} + +func (*Subtraction) Do(x, y int) Result { + return Int(x - y) +} + +type Multiplication struct{} + +func (*Multiplication) Kind() string { + return "multiplication" +} + +func (*Multiplication) Do(x, y int) Result { + return Int(x * y) +} + +type DivisionResult struct { + Quotient int + Remainder int +} + +func (d *DivisionResult) Outcome() string { + return fmt.Sprintf("(quotient: %d, remainder: %d)", d.Quotient, d.Remainder) +} + +type InvalidDenominator struct{} + +func (i *InvalidDenominator) Outcome() string { + return "Invalid denominator. It must be not zero" +} + +type Division struct{} + +func (d *Division) Kind() string { + return "division" +} + +func (d *Division) Do(x, y int) Result { + if y == 0 { + return &InvalidDenominator{} + } + q, r := x/y, x%y + return &DivisionResult{q, r} +} diff --git a/go/study/ch02_first_cli_app/calc_test.go b/go/study/ch02_first_cli_app/calc_test.go new file mode 100644 index 00000000..5d22ad99 --- /dev/null +++ b/go/study/ch02_first_cli_app/calc_test.go @@ -0,0 +1,48 @@ +package main + +import "testing" + +func TestAddtion(t *testing.T) { + calc := &Addition{} + if calc.Kind() != "addition" { + t.FailNow() + } + if calc.Do(1, 2) != Int(3) { + t.FailNow() + } +} + +func TestSubtraction(t *testing.T) { + calc := &Subtraction{} + if calc.Kind() != "subtraction" { + t.FailNow() + } + if calc.Do(2, 1) != Int(1) { + t.FailNow() + } +} + +func TestMultiplication(t *testing.T) { + calc := &Multiplication{} + if calc.Kind() != "multiplication" { + t.FailNow() + } + if calc.Do(2, 3) != Int(6) { + t.FailNow() + } +} + +func TestDivision(t *testing.T) { + calc := &Division{} + if calc.Kind() != "division" { + t.FailNow() + } + if _, ok := calc.Do(2, 0).(*InvalidDenominator); !ok { + t.FailNow() + } + if r, ok := calc.Do(10, 3).(*DivisionResult); ok { + if r.Quotient != 3 || r.Remainder != 1 { + t.FailNow() + } + } +} diff --git a/go/study/ch02_first_cli_app/go.mod b/go/study/ch02_first_cli_app/go.mod new file mode 100644 index 00000000..b8982bd0 --- /dev/null +++ b/go/study/ch02_first_cli_app/go.mod @@ -0,0 +1,3 @@ +module github.com/tecyokomichi/WebAppLearning/go/study/ch02_first_cli_app + +go 1.19 diff --git a/go/study/ch02_first_cli_app/main.go b/go/study/ch02_first_cli_app/main.go new file mode 100644 index 00000000..d934c9cc --- /dev/null +++ b/go/study/ch02_first_cli_app/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "os" + "strconv" +) + +var calcMap = map[string]Calculation{ + "add": &Addition{}, + "subtract": &Subtraction{}, + "multiply": &Multiplication{}, + "divide": &Division{}, +} + +func main() { + if len(os.Args) < 4 || 4 < len(os.Args) { + showHelp() + os.Exit(1) + } else if len(os.Args) == 4 { + calc, ok := calcMap[os.Args[1]] + if !ok { + showHelp() + os.Exit(1) + } + x, e := parseInt(os.Args[2]) + if e != nil { + fmt.Printf("%s\n", e.Error()) + os.Exit(1) + } + y, e := parseInt(os.Args[3]) + if e != nil { + fmt.Printf("%s\n", e.Error()) + os.Exit(1) + } + fmt.Printf("%s: %s\n", calc.Kind(), calc.Do(x, y).Outcome()) + os.Exit(0) + } +} + +func showHelp() { + fmt.Println("USAGE:") + fmt.Println("./ch02_first_cli (add|subtract|multiply|divide) X Y") + fmt.Println(" Shows the result of calculation with X and Y") + fmt.Println(" X and Y must be number") +} + +func parseInt(s string) (int, error) { + r, err := strconv.Atoi(s) + if err != nil { + return 0, fmt.Errorf("ERROR: %q is not a number", s) + } + return r, nil +}