Skip to content

Commit

Permalink
Fixes #12 - adds mock device, more robust tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rzetterberg committed Mar 17, 2018
1 parent e83bd7a commit 60ed2aa
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 97 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

## [0.3.0] - 2017-01-21
## [0.3.0] - 2018-01-21

### Changed
- Sends expected data lines with each OBD command to speed up communication
Expand Down
20 changes: 11 additions & 9 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Let's start by looking at some example of how you use the library.

** Example usage

Note: these examples are performed on Linux. If you are using another platform
*Note:* these examples are performed on Linux. If you are using another platform
there should be minimal changes, but they are not documented yet. Go ahead
and put a :+1: on issue #11 if you think this should be prioritized.

Expand Down Expand Up @@ -106,7 +106,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand All @@ -124,8 +124,10 @@ func main() {
}
#+END_SRC

When I run this executable on my machine with the ELM327 device plugged in
I get the following result:
*Note:* These examples uses the function ~NewTestDevice~, which uses a mocked
ELM327 device. To use a real ELM327 device, you instead use ~NewDevice~. The
reason why a mocked device is used is because the examples should be runnable
without using a real device.

#+BEGIN_EXAMPLE
$ go run example.go
Expand Down Expand Up @@ -170,7 +172,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand Down Expand Up @@ -212,7 +214,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand Down Expand Up @@ -267,7 +269,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand All @@ -284,7 +286,7 @@ func main() {
allCommands := elmobd.GetSensorCommands()
carCommands := supported.FilterSupported(allCommands)

fmt.Printf("%d of %d commands supported:\n", carCommands, allCommands)
fmt.Printf("%d of %d commands supported:\n", len(carCommands), len(allCommands))

for _, cmd := range carCommands {
fmt.Printf("- %s supported\n", cmd.Key())
Expand All @@ -306,7 +308,7 @@ structure.

The project uses quarterly milestones to plan upcoming changes. The current
quarter will focus on improving documentation. To see the details of what
will be done see the milestone [[https://github.com/rzetterberg/elmobd/milestone/2%5D%5D][2018 Q1]].
will be done see the milestone [[https://github.com/rzetterberg/elmobd/milestone/2][2018 Q1]].

Changes of the library are tracked in the [[file:CHANGELOG.md][CHANGELOG]].

Expand Down
4 changes: 2 additions & 2 deletions automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ def check(args):
command(['golint'])

def test(args):
logger.info('Running unit tests')
command(['go', 'test', './...'])
logger.info('Running benchmarks, unit tests and examples')
command(['go', 'test', '-bench', '.', './...'])

example_files = glob.glob('./examples/**/*.go', recursive=True)

Expand Down
81 changes: 52 additions & 29 deletions device.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,27 +167,40 @@ func (res *Result) PayloadAsByte() (byte, error) {
return uint8(result), nil
}

// RawResult represents the raw text output of running a raw command,
// including information used in debugging to show what input caused what
// error, how long the command took, etc.
type RawResult interface {
Failed() bool
GetError() error
GetOutputs() []string
FormatOverview() string
}

// RawDevice represent the low level device, which can either be the real
// implementation or a mock implementation used for testing.
type RawDevice interface {
RunCommand(string) RawResult
}

// Device represents the connection to a ELM327 device. This is the data type
// you use to run commands on the connected ELM327 device, see NewDevice for
// creating a Device and RunOBDCommand for running commands.
type Device struct {
rawDevice *RawDevice
rawDevice RawDevice
outputDebug bool
}

// NewDevice constructs a Device by initilizing the serial connection and
// setting the protocol to talk with the car to "automatic".
func NewDevice(devicePath string, debug bool) (*Device, error) {
rawDev, err := NewRawDevice(devicePath)
rawDev, err := NewRealDevice(devicePath)

if err != nil {
return nil, err
}

dev := Device{
rawDev,
debug,
}
dev := Device{rawDev, debug}

err = dev.SetAutomaticProtocol()

Expand All @@ -198,25 +211,34 @@ func NewDevice(devicePath string, debug bool) (*Device, error) {
return &dev, nil
}

// NewTestDevice constructs a Device which is using a mocked RawDevice.
func NewTestDevice(devicePath string, debug bool) (*Device, error) {
dev := Device{&MockDevice{}, debug}

return &dev, nil
}

// SetAutomaticProtocol tells the ELM327 device to automatically discover what
// protocol to talk to the car with. How the protocol is chhosen is something
// that the ELM327 does internally. If you're interested in how this works you
// can look in the data sheet linked in the beginning of the package description.
func (dev *Device) SetAutomaticProtocol() error {
res := dev.rawDevice.RunCommand("ATSP0")
rawRes := dev.rawDevice.RunCommand("ATSP0")

if res.Error != nil {
return res.Error
if rawRes.Failed() {
return rawRes.GetError()
}

if dev.outputDebug {
fmt.Println(res.FormatOverview())
fmt.Println(rawRes.FormatOverview())
}

if res.Outputs[0] != "OK" {
outputs := rawRes.GetOutputs()

if outputs[0] != "OK" {
return fmt.Errorf(
"Expected OK response, got: %q",
res.Outputs[0],
outputs[0],
)
}

Expand All @@ -226,17 +248,18 @@ func (dev *Device) SetAutomaticProtocol() error {
// GetVersion gets the version of the connected ELM327 device. The latest
// version being v2.2.
func (dev *Device) GetVersion() (string, error) {
res := dev.rawDevice.RunCommand("AT@1")
rawRes := dev.rawDevice.RunCommand("AT@1")

if res.Error != nil {
return "", res.Error
if rawRes.Failed() {
return "", rawRes.GetError()
}

if dev.outputDebug {
fmt.Println(res.FormatOverview())
fmt.Println(rawRes.FormatOverview())
}

version := res.Outputs[0][:]
outputs := rawRes.GetOutputs()
version := outputs[0][:]

return strings.Trim(version, " "), nil
}
Expand Down Expand Up @@ -290,17 +313,17 @@ func (dev *Device) CheckSupportedCommands() (*SupportedCommands, error) {

// CheckSupportedPart checks the availability of a range of 32 commands.
func (dev *Device) CheckSupportedPart(cmd OBDCommand) (OBDCommand, error) {
rawResult := dev.rawDevice.RunCommand(cmd.ToCommand())
rawRes := dev.rawDevice.RunCommand(cmd.ToCommand())

if rawResult.Error != nil {
return cmd, rawResult.Error
if rawRes.Failed() {
return cmd, rawRes.GetError()
}

if dev.outputDebug {
fmt.Println(rawResult.FormatOverview())
fmt.Println(rawRes.FormatOverview())
}

result, err := parseOBDResponse(cmd, rawResult.Outputs)
result, err := parseOBDResponse(cmd, rawRes.GetOutputs())

if err != nil {
return cmd, err
Expand All @@ -320,17 +343,17 @@ func (dev *Device) CheckSupportedPart(cmd OBDCommand) (OBDCommand, error) {
// RunOBDCommand runs the given OBDCommand on the connected ELM327 device and
// populates the OBDCommand with the parsed output from the device.
func (dev *Device) RunOBDCommand(cmd OBDCommand) (OBDCommand, error) {
rawResult := dev.rawDevice.RunCommand(cmd.ToCommand())
rawRes := dev.rawDevice.RunCommand(cmd.ToCommand())

if rawResult.Error != nil {
return cmd, rawResult.Error
if rawRes.Failed() {
return cmd, rawRes.GetError()
}

if dev.outputDebug {
fmt.Println(rawResult.FormatOverview())
fmt.Println(rawRes.FormatOverview())
}

result, err := parseOBDResponse(cmd, rawResult.Outputs)
result, err := parseOBDResponse(cmd, rawRes.GetOutputs())

if err != nil {
return cmd, err
Expand All @@ -352,13 +375,13 @@ func (dev *Device) RunManyOBDCommands(commands []OBDCommand) ([]OBDCommand, erro
var result []OBDCommand

for _, cmd := range commands {
res, err := dev.RunOBDCommand(cmd)
processed, err := dev.RunOBDCommand(cmd)

if err != nil {
return []OBDCommand{}, err
}

result = append(result, res)
result = append(result, processed)
}

return result, nil
Expand Down
18 changes: 1 addition & 17 deletions device_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package elmobd

import (
"fmt"
"testing"
)

Expand Down Expand Up @@ -41,14 +40,6 @@ func BenchmarkParseOBDResponse2(b *testing.B) {
* Tests
*/

func assertEqual(t *testing.T, a interface{}, b interface{}) {
if a == b {
return
}

t.Fatal(fmt.Sprintf("%v != %v", a, b))
}

func TestToCommand(t *testing.T) {
assertEqual(t, NewPart1Supported().ToCommand(), "01001")
assertEqual(t, NewEngineLoad().ToCommand(), "01041")
Expand Down Expand Up @@ -174,13 +165,6 @@ func TestParseOBDResponse(t *testing.T) {
}

for _, curr := range scenarios {
_, err := parseOBDResponse(
curr.command,
curr.outputs,
)

if err != nil {
t.Error("Failed parsing", err)
}
assertOBDParseSuccess(t, curr.command, curr.outputs)
}
}
2 changes: 1 addition & 1 deletion examples/example_1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand Down
2 changes: 1 addition & 1 deletion examples/example_2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand Down
2 changes: 1 addition & 1 deletion examples/example_3/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand Down
4 changes: 2 additions & 2 deletions examples/example_4/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {

flag.Parse()

dev, err := elmobd.NewDevice(*serialPath, false)
dev, err := elmobd.NewTestDevice(*serialPath, false)

if err != nil {
fmt.Println("Failed to create new device", err)
Expand All @@ -32,7 +32,7 @@ func main() {
allCommands := elmobd.GetSensorCommands()
carCommands := supported.FilterSupported(allCommands)

fmt.Printf("%d of %d commands supported:\n", carCommands, allCommands)
fmt.Printf("%d of %d commands supported:\n", len(carCommands), len(allCommands))

for _, cmd := range carCommands {
fmt.Printf("- %s supported\n", cmd.Key())
Expand Down
Loading

0 comments on commit 60ed2aa

Please sign in to comment.