Skip to content

Commit

Permalink
🎨 Refactor tests for godocs
Browse files Browse the repository at this point in the history
  • Loading branch information
phedoreanu committed Aug 8, 2016
1 parent 077d81d commit a73ef46
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
engines:
govet:
enabled: true
golint:
enabled: true

Expand Down
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# hoover
Hoover is a little Go room cleaning program.

[![Build Status](https://travis-ci.org/phedoreanu/hoover.svg?branch=master)](https://travis-ci.org/phedoreanu/hoover) [![Coverage Status](https://coveralls.io/repos/github/phedoreanu/hoover/badge.svg)](https://coveralls.io/github/phedoreanu/hoover) [![Code Climate](https://codeclimate.com/github/phedoreanu/hoover/badges/gpa.svg)](https://codeclimate.com/github/phedoreanu/hoover) [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org)
[![Build Status](https://travis-ci.org/phedoreanu/hoover.svg?branch=master)](https://travis-ci.org/phedoreanu/hoover) [![Coverage Status](https://coveralls.io/repos/github/phedoreanu/hoover/badge.svg)](https://coveralls.io/github/phedoreanu/hoover) [![Code Climate](https://codeclimate.com/github/phedoreanu/hoover/badges/gpa.svg)](https://codeclimate.com/github/phedoreanu/hoover) [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) [![GoDoc](https://godoc.org/github.com/phedoreanu/hoover?status.svg)](https://godoc.org/github.com/phedoreanu/hoover/robot)

###Installation
Hoover requires Go 1.5 or later.
Expand All @@ -13,17 +13,21 @@ go get -u github.com/phedoreanu/hoover
Invoke `hoover` in the same directory as `input.txt`.

###Testing
To run the tests:
```
$ go test github.com/phedoreanu/hoover
ok github.com/phedoreanu/hoover 0.005s
```
As always, if you are running the `go` tool from the package directory, you can omit the package path:

###Cyclomatic complexity
```sh
$ mccabe-cyclomatic -p github.com/phedoreanu/hoover
6
```
$ go test
PASS
ok github.com/phedoreanu/hoover 0.005s

```sh
$ gocyclo -top 3 -avg .
4 robot (*Hoover).Vacuum robot/robot.go:72:1
3 robot (*Patch).Update robot/robot.go:31:1
2 robot (*Hoover).move robot/robot.go:56:1
Average: 1.46
```
###Improvements
* Add command-line flags for more verbose output and multiple input files
* Docker + RESTful API
101 changes: 49 additions & 52 deletions hoover.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package main contains the source code of a hoover
// Package main contains the source code of an imaginary robot Hoover
package main

import (
Expand All @@ -8,12 +8,13 @@ import (
"io/ioutil"
"strconv"
"strings"
"flag"
)

// Patch defines a square in the room
// with X and Y coordinates
type Patch struct {
X, Y uint16
X, Y int
}

// String handles Patch pretty print
Expand All @@ -27,81 +28,77 @@ func NewPatch(s string) Patch {
return Patch{X: parseUInt16(c[0]), Y: parseUInt16(c[1])}
}

// Update calculates the next Patch to go to
func (p *Patch) Update(n, b *Patch) {
if p.X >= b.X && p.Y >= b.Y { // skid in place
return
}
p.X += n.X
p.Y += n.Y
}

// Hoover is an imaginary robotic hoover
type Hoover struct {
Location Patch
Room map[Patch]bool
Cleaned, Boundary uint16
Steps []byte
Location, Boundary Patch
Room map[Patch]bool
Dirty int
}

// String handles *Hoover pretty print
func (h *Hoover) String() string {
return fmt.Sprintf("%s\n%d", h.Location, h.Cleaned)
return fmt.Sprintf("%s\n%d", h.Location, h.Dirty-len(h.Room))
}

func parseUInt16(s string) uint16 {
func parseUInt16(s string) int {
ui64, _ := strconv.ParseUint(s, 10, 16)
return uint16(ui64)
return int(ui64)
}

func (h *Hoover) clean() {
for _, s := range h.Steps {
switch {
case h.Location.Y < h.Boundary && s == 78: // N
h.Location.Y++
case h.Location.Y > 0 && s == 83: // S
h.Location.Y--
case h.Location.X < h.Boundary && s == 69: // E
h.Location.X++
case h.Location.X > 0 && s == 87: // W
h.Location.X--
}

if h.Room[h.Location] {
h.Cleaned++
delete(h.Room, h.Location)
}
func (h *Hoover) move(s string) {
directions := map[byte]*Patch{
78: {X: 0, Y: 1}, // N
83: {X: 0, Y: -1}, // S
69: {X: 1, Y: 0}, // E
87: {X: -1, Y: 0}, // W
}

loc := &h.Location
for _, d := range []byte(s) {
loc.Update(directions[d], &h.Boundary)
delete(h.Room, h.Location) // clean dirty Patches
}
}

// Vacuum hoovers the room `filename`
func (h *Hoover) Vacuum(filename string) string {
data, _ := ioutil.ReadFile(filename)
if len(data) == 0 {
return h.String()
}
scanner := bufio.NewScanner(bytes.NewReader(data))

lineNo := 0
var cfg []string
for scanner.Scan() {
if len(scanner.Bytes()) == 0 { // skip empty lines
continue
}

b := scanner.Bytes()[0]
switch {
case 48 <= b && b <= 57: // numbers
switch lineNo {
case 0:
h.Room = make(map[Patch]bool)
h.Boundary = parseUInt16(strings.Split(scanner.Text(), " ")[0])
case 1:
h.Location = NewPatch(scanner.Text())
default:
dirtyPatch := NewPatch(scanner.Text())
h.Room[dirtyPatch] = true
}
case 65 <= b && b <= 90: // characters
h.Steps = scanner.Bytes()
}
lineNo++
cfg = append(cfg, scanner.Text())
}

h.clean()
h.Boundary = NewPatch(cfg[0])
h.Location = NewPatch(cfg[1])

h.Room = make(map[Patch]bool)
for _, s := range cfg[2 : len(cfg)-1] {
dirtyPatch := NewPatch(s)
h.Room[dirtyPatch] = true
}
h.Dirty = len(h.Room)

h.move(cfg[len(cfg)-1])

return h.String()
}

func main() {
res := new(Hoover).Vacuum("input.txt")

fmt.Println(res)
var input = flag.String("input", "input.txt", "input filename")
flag.Parse()
fmt.Println(new(Hoover).Vacuum(*input))
}
41 changes: 25 additions & 16 deletions hoover_test.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
package main

import "testing"
import "fmt"

func TestHoover(t *testing.T) {
func Example() {
fmt.Println(new(Hoover).Vacuum("input.txt"))
// Output:
// 1 3
// 1
}

func ExampleHoover_Vacuum() {
fmt.Println(new(Hoover).Vacuum("input_room_clean.txt"))
// Output:
// 1 3
// 0
}

cases := []struct {
in, want string
}{
{"input.txt", "1 3\n1"},
{"input_boundary.txt", "2 2\n2"},
{"input_room_clean.txt", "1 3\n0"},
{"input_empty.txt", "0 0\n0"},
}
func ExampleEmptyRoom() {
fmt.Println(new(Hoover).Vacuum("input_emptyXX.txt"))
// Output:
// 0 0
// 0
}

for _, c := range cases {
got := new(Hoover).Vacuum(c.in)
if got != c.want {
t.Errorf("Vacuum(%q) == %q, want %q", c.in, got, c.want)
}
}
func ExampleBoundary() {
fmt.Println(new(Hoover).Vacuum("input_boundary.txt"))
// Output:
// 2 2
// 2
}
4 changes: 0 additions & 4 deletions input_empty.txt
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@




0 comments on commit a73ef46

Please sign in to comment.