gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/grovepi_driver_test.go (about)

     1  package i2c
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"gobot.io/x/gobot/v2"
     9  	"gobot.io/x/gobot/v2/drivers/aio"
    10  	"gobot.io/x/gobot/v2/drivers/gpio"
    11  	"gobot.io/x/gobot/v2/gobottest"
    12  )
    13  
    14  // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver
    15  // and tests all implementations, so no further tests needed here for gobot.Driver interface
    16  var _ gobot.Driver = (*GrovePiDriver)(nil)
    17  
    18  // must implement the DigitalReader interface
    19  var _ gpio.DigitalReader = (*GrovePiDriver)(nil)
    20  
    21  // must implement the DigitalWriter interface
    22  var _ gpio.DigitalWriter = (*GrovePiDriver)(nil)
    23  
    24  // must implement the AnalogReader interface
    25  var _ aio.AnalogReader = (*GrovePiDriver)(nil)
    26  
    27  // must implement the AnalogWriter interface
    28  var _ aio.AnalogWriter = (*GrovePiDriver)(nil)
    29  
    30  // must implement the Adaptor interface
    31  var _ gobot.Adaptor = (*GrovePiDriver)(nil)
    32  
    33  func initGrovePiDriverWithStubbedAdaptor() (*GrovePiDriver, *i2cTestAdaptor) {
    34  	adaptor := newI2cTestAdaptor()
    35  	return NewGrovePiDriver(adaptor), adaptor
    36  }
    37  
    38  func TestNewGrovePiDriver(t *testing.T) {
    39  	var di interface{} = NewGrovePiDriver(newI2cTestAdaptor())
    40  	d, ok := di.(*GrovePiDriver)
    41  	if !ok {
    42  		t.Errorf("NewGrovePiDriver() should have returned a *GrovePiDriver")
    43  	}
    44  	gobottest.Refute(t, d.Driver, nil)
    45  	gobottest.Assert(t, strings.HasPrefix(d.Name(), "GrovePi"), true)
    46  	gobottest.Assert(t, d.defaultAddress, 0x04)
    47  	gobottest.Refute(t, d.pins, nil)
    48  }
    49  
    50  func TestGrovePiOptions(t *testing.T) {
    51  	// This is a general test, that options are applied in constructor by using the common WithBus() option and
    52  	// least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)".
    53  	d := NewGrovePiDriver(newI2cTestAdaptor(), WithBus(2))
    54  	gobottest.Assert(t, d.GetBusOrDefault(1), 2)
    55  }
    56  
    57  func TestGrovePiSomeRead(t *testing.T) {
    58  	// arrange
    59  	var tests = map[string]struct {
    60  		usedPin          int
    61  		wantWritten      []uint8
    62  		simResponse      [][]uint8
    63  		wantErr          error
    64  		wantCallsRead    int
    65  		wantResult       int
    66  		wantResultF1     float32
    67  		wantResultF2     float32
    68  		wantResultString string
    69  	}{
    70  		"DigitalRead": {
    71  			usedPin:       2,
    72  			wantWritten:   []uint8{commandSetPinMode, 2, 0, 0, commandReadDigital, 2, 0, 0},
    73  			simResponse:   [][]uint8{{0}, {commandReadDigital, 3}},
    74  			wantCallsRead: 2,
    75  			wantResult:    3,
    76  		},
    77  		"AnalogRead": {
    78  			usedPin:     3,
    79  			wantWritten: []uint8{commandSetPinMode, 3, 0, 0, commandReadAnalog, 3, 0, 0},
    80  			simResponse: [][]uint8{{0}, {commandReadAnalog, 4, 5}},
    81  			wantResult:  1029,
    82  		},
    83  		"UltrasonicRead": {
    84  			usedPin:     4,
    85  			wantWritten: []uint8{commandSetPinMode, 4, 0, 0, commandReadUltrasonic, 4, 0, 0},
    86  			simResponse: [][]uint8{{0}, {commandReadUltrasonic, 5, 6}},
    87  			wantResult:  1281,
    88  		},
    89  		"FirmwareVersionRead": {
    90  			wantWritten:      []uint8{commandReadFirmwareVersion, 0, 0, 0},
    91  			simResponse:      [][]uint8{{commandReadFirmwareVersion, 7, 8, 9}},
    92  			wantResultString: "7.8.9",
    93  		},
    94  		"DHTRead": {
    95  			usedPin:      5,
    96  			wantWritten:  []uint8{commandSetPinMode, 5, 0, 0, commandReadDHT, 5, 1, 0},
    97  			simResponse:  [][]uint8{{0}, {commandReadDHT, 164, 112, 69, 193, 20, 174, 54, 66}},
    98  			wantResultF1: -12.34,
    99  			wantResultF2: 45.67,
   100  		},
   101  		"DigitalRead_error_wrong_return_cmd": {
   102  			usedPin:     15,
   103  			wantWritten: []uint8{commandSetPinMode, 15, 0, 0, commandReadDigital, 15, 0, 0},
   104  			simResponse: [][]uint8{{0}, {0, 2}},
   105  			wantErr:     fmt.Errorf("answer (0) was not for command (1)"),
   106  		},
   107  		"AnalogRead_error_wrong_return_cmd": {
   108  			usedPin:     16,
   109  			wantWritten: []uint8{commandSetPinMode, 16, 0, 0, commandReadAnalog, 16, 0, 0},
   110  			simResponse: [][]uint8{{0}, {0, 3, 4}},
   111  			wantErr:     fmt.Errorf("answer (0) was not for command (3)"),
   112  		},
   113  		"UltrasonicRead_error_wrong_return_cmd": {
   114  			usedPin:     17,
   115  			wantWritten: []uint8{commandSetPinMode, 17, 0, 0, commandReadUltrasonic, 17, 0, 0},
   116  			simResponse: [][]uint8{{0}, {0, 5, 6}},
   117  			wantErr:     fmt.Errorf("answer (0) was not for command (7)"),
   118  		},
   119  		"FirmwareVersionRead_error_wrong_return_cmd": {
   120  			wantWritten: []uint8{commandReadFirmwareVersion, 0, 0, 0},
   121  			simResponse: [][]uint8{{0, 7, 8, 9}},
   122  			wantErr:     fmt.Errorf("answer (0) was not for command (8)"),
   123  		},
   124  		"DHTRead_error_wrong_return_cmd": {
   125  			usedPin:     18,
   126  			wantWritten: []uint8{commandSetPinMode, 18, 0, 0, commandReadDHT, 18, 1, 0},
   127  			simResponse: [][]uint8{{0}, {0, 164, 112, 69, 193, 20, 174, 54, 66}},
   128  			wantErr:     fmt.Errorf("answer (0) was not for command (40)"),
   129  		},
   130  		"DigitalRead_error_wrong_data_count": {
   131  			usedPin:     28,
   132  			wantWritten: []uint8{commandSetPinMode, 28, 0, 0, commandReadDigital, 28, 0, 0},
   133  			simResponse: [][]uint8{{0}, {commandReadDigital, 2, 3}},
   134  			wantErr:     fmt.Errorf("read count mismatch (3 should be 2)"),
   135  		},
   136  	}
   137  	for name, tc := range tests {
   138  		t.Run(name, func(t *testing.T) {
   139  			g, a := initGrovePiDriverWithStubbedAdaptor()
   140  			g.Start()
   141  			a.written = []byte{} // reset writes of former test and start
   142  			numCallsRead := 0
   143  			a.i2cReadImpl = func(bytes []byte) (i int, e error) {
   144  				numCallsRead++
   145  				copy(bytes, tc.simResponse[numCallsRead-1])
   146  				return len(tc.simResponse[numCallsRead-1]), nil
   147  			}
   148  			var got int
   149  			var gotF1, gotF2 float32
   150  			var gotString string
   151  			var err error
   152  			// act
   153  			switch {
   154  			case strings.Contains(name, "DigitalRead"):
   155  				got, err = g.DigitalRead(fmt.Sprintf("%d", tc.usedPin))
   156  			case strings.Contains(name, "AnalogRead"):
   157  				got, err = g.AnalogRead(fmt.Sprintf("%d", tc.usedPin))
   158  			case strings.Contains(name, "UltrasonicRead"):
   159  				got, err = g.UltrasonicRead(fmt.Sprintf("%d", tc.usedPin), 2)
   160  			case strings.Contains(name, "FirmwareVersionRead"):
   161  				gotString, err = g.FirmwareVersionRead()
   162  			case strings.Contains(name, "DHTRead"):
   163  				gotF1, gotF2, err = g.DHTRead(fmt.Sprintf("%d", tc.usedPin), 1, 2)
   164  			default:
   165  				t.Errorf("unknown command %s", name)
   166  				return
   167  			}
   168  			// assert
   169  			gobottest.Assert(t, err, tc.wantErr)
   170  			gobottest.Assert(t, a.written, tc.wantWritten)
   171  			gobottest.Assert(t, numCallsRead, len(tc.simResponse))
   172  			gobottest.Assert(t, got, tc.wantResult)
   173  			gobottest.Assert(t, gotF1, tc.wantResultF1)
   174  			gobottest.Assert(t, gotF2, tc.wantResultF2)
   175  			gobottest.Assert(t, gotString, tc.wantResultString)
   176  		})
   177  	}
   178  }
   179  
   180  func TestGrovePiSomeWrite(t *testing.T) {
   181  	// arrange
   182  	var tests = map[string]struct {
   183  		usedPin     int
   184  		usedValue   int
   185  		wantWritten []uint8
   186  		simResponse []uint8
   187  	}{
   188  		"DigitalWrite": {
   189  			usedPin:     2,
   190  			usedValue:   3,
   191  			wantWritten: []uint8{commandSetPinMode, 2, 1, 0, commandWriteDigital, 2, 3, 0},
   192  			simResponse: []uint8{4},
   193  		},
   194  		"AnalogWrite": {
   195  			usedPin:     5,
   196  			usedValue:   6,
   197  			wantWritten: []uint8{commandSetPinMode, 5, 1, 0, commandWriteAnalog, 5, 6, 0},
   198  			simResponse: []uint8{7},
   199  		},
   200  	}
   201  	for name, tc := range tests {
   202  		t.Run(name, func(t *testing.T) {
   203  			g, a := initGrovePiDriverWithStubbedAdaptor()
   204  			g.Start()
   205  			a.written = []byte{} // reset writes of former test and start
   206  			a.i2cReadImpl = func(bytes []byte) (i int, e error) {
   207  				copy(bytes, tc.simResponse)
   208  				return len(bytes), nil
   209  			}
   210  			var err error
   211  			// act
   212  			switch name {
   213  			case "DigitalWrite":
   214  				err = g.DigitalWrite(fmt.Sprintf("%d", tc.usedPin), byte(tc.usedValue))
   215  			case "AnalogWrite":
   216  				err = g.AnalogWrite(fmt.Sprintf("%d", tc.usedPin), tc.usedValue)
   217  			default:
   218  				t.Errorf("unknown command %s", name)
   219  				return
   220  			}
   221  			// assert
   222  			gobottest.Assert(t, err, nil)
   223  			gobottest.Assert(t, a.written, tc.wantWritten)
   224  		})
   225  	}
   226  }
   227  
   228  func TestGrovePi_getPin(t *testing.T) {
   229  	gobottest.Assert(t, getPin("a1"), "1")
   230  	gobottest.Assert(t, getPin("A16"), "16")
   231  	gobottest.Assert(t, getPin("D3"), "3")
   232  	gobottest.Assert(t, getPin("d22"), "22")
   233  	gobottest.Assert(t, getPin("22"), "22")
   234  }