// Code generated by mockery v1.0.0. DO NOT EDIT. package main import mock "github.com/stretchr/testify/mock" // mockExecuter is an autogenerated mock type for the executer type type mockExecuter struct { mock.Mock } // covertOutputToCoverage provides a mock function with given fields: termOutput func (_m *mockExecuter) covertOutputToCoverage(termOutput string) ([]testLine, error) { ret := _m.Called(termOutput) var r0 []testLine if rf, ok := ret.Get(0).(func(string) []testLine); ok { r0 = rf(termOutput) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]testLine) } } var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(termOutput) } else { r1 = ret.Error(1) } return r0, r1 } // runGoTest provides a mock function with given fields: func (_m *mockExecuter) runGoTest() (string, error) { ret := _m.Called() var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() } else { r0 = ret.Get(0).(string) } var r1 error if rf, ok := ret.Get(1).(func() error); ok { r1 = rf() } else { r1 = ret.Error(1) } return r0, r1 } // validateTestOutput provides a mock function with given fields: tl, o func (_m *mockExecuter) validateTestOutput(tl []testLine, o string) error { ret := _m.Called(tl, o) var r0 error if rf, ok := ret.Get(0).(func([]testLine, string) error); ok { r0 = rf(tl, o) } else { r0 = ret.Error(0) } return r0 }
// Package main contains code to do with ensuring coverage is over 80% package main import ( "fmt" "log" "os/exec" "strconv" "strings" ) const ( minPercentCov = 80.0 coverageStringNotFound = -1.0 firstItemIndex = 1 floatByteSize = 64 emptySliceLen = 0 lenOfPercentChar = 1 indexOfEmptyLine = 1 ) var excludedPkgs = map[string]bool{ "github.com/gowhale/go-circuit-diagram": true, "github.com/gowhale/go-circuit-diagram/pkg/common": true, "github.com/gowhale/go-circuit-diagram/cmd/anode-matrix": true, } func main() { if err := run(&execute{}); err != nil { log.Fatalln(err) } log.Println("Tests=PASS Coverage=PASS") } //go:generate go run github.com/vektra/mockery/cmd/mockery -name executer -inpkg --filename executer_mock.go type executer interface { runGoTest() (string, error) covertOutputToCoverage(termOutput string) ([]testLine, error) validateTestOutput(tl []testLine, o string) error } func run(e executer) error { output, err := e.runGoTest() if err != nil { log.Println(output) return err } tl, err := e.covertOutputToCoverage(output) if err != nil { return err } return e.validateTestOutput(tl, output) } var execCommand = exec.Command type execute struct{} func (*execute) runGoTest() (string, error) { cmd := execCommand("go", "test", "./...", "--cover") output, err := cmd.CombinedOutput() termOutput := string(output) return termOutput, err } type testLine struct { pkgName string coverage float64 coverLine bool } func getCoverage(line string) (testLine, error) { if !strings.Contains(line, "go: downloading") { pkgName := strings.Fields(line)[firstItemIndex] if _, ok := excludedPkgs[pkgName]; !ok { coverageIndex := strings.Index(line, "coverage: ") if coverageIndex != coverageStringNotFound { lineFields := strings.Fields(line[coverageIndex:]) pkgPercentStr := lineFields[firstItemIndex][:len(lineFields[firstItemIndex])-lenOfPercentChar] pkgPercentFloat, err := strconv.ParseFloat(pkgPercentStr, floatByteSize) if err != nil { return testLine{}, err } log.Println(pkgPercentStr) return testLine{pkgName: pkgName, coverage: pkgPercentFloat, coverLine: true}, nil } return testLine{pkgName: pkgName, coverage: coverageStringNotFound, coverLine: true}, nil } } return testLine{coverLine: false}, nil } func (*execute) covertOutputToCoverage(termOutput string) ([]testLine, error) { testStruct := []testLine{} lines := strings.Split(termOutput, "\n") for _, line := range lines[:len(lines)-indexOfEmptyLine] { tl, err := getCoverage(line) if err != nil { return nil, err } if tl.coverLine { testStruct = append(testStruct, tl) } } return testStruct, nil } func (*execute) validateTestOutput(tl []testLine, o string) error { invalidOutputs := []string{} for _, line := range tl { switch { case !line.coverLine: invalidOutputs = append(invalidOutputs, fmt.Sprintf("pkg=%s is missing tests", line.pkgName)) case line.coverage < minPercentCov: invalidOutputs = append(invalidOutputs, fmt.Sprintf("pkg=%s cov=%f under the %f%% minimum line coverage", line.pkgName, line.coverage, minPercentCov)) } } if len(invalidOutputs) == emptySliceLen { return nil } log.Println(o) log.Println("###############################") log.Println("invalid pkg's:") for i, invalid := range invalidOutputs { log.Printf("id=%d problem=%s", i, invalid) } log.Println("###############################") return fmt.Errorf("the following pkgs are not valid: %+v", invalidOutputs) }
// Package canvas is contains code for drawing components on package canvas import ( "fmt" "image" "image/color" "log" "github.com/gowhale/go-circuit-diagram/pkg/common" "github.com/gowhale/go-circuit-diagram/pkg/components" ) // Board represents a board to add components to type Board struct { name string width, height int magnification int elements []components.Element } // NewBoard returns a new Board struct to add components to func NewBoard(name string, width, height, magnification int) Board { return Board{ name: name, width: width, height: height, magnification: magnification, } } // AddElement adds an elemnt which is rendered when Draw is called func (b *Board) AddElement(elem components.Element) { b.elements = append(b.elements, elem) } // ElementCount returns the amount of elements on a board func (b *Board) ElementCount() int { return len(b.elements) } func enlargeCoordintes(coords [][]int, scale int) [][]int { newCoords := [][]int{} for _, cord := range coords { x := cord[0] y := cord[1] for i := 0; i < scale; i++ { for j := 0; j < scale; j++ { newCoords = append(newCoords, []int{(x * (scale - 1)) + x + i, (y * (scale - 1)) + y + j}) } } } return newCoords } func (b *Board) fillCoordinates(img *image.RGBA, elem components.Element) error { cords, err := elem.GetCoordinates() if err != nil { return err } cords = enlargeCoordintes(cords, b.magnification) warning := false for _, cord := range cords { if cord[0] < (b.width*b.magnification) && cord[1] < (b.height*b.magnification) { img.Set(cord[0], cord[1], elem.GetColour()) } else { warning = true } } if warning { log.Println("WARNING: some of this elements contents will not be shown as out of bounds") } return nil } // Draw creates image with all components drawn on func (b *Board) Draw(o common.OS) error { width := b.width * b.magnification height := b.height * b.magnification upLeft := image.Point{0, 0} lowRight := image.Point{width, height} img := image.NewRGBA(image.Rectangle{upLeft, lowRight}) // Set color for each pixel. for x := 0; x < width; x++ { for y := 0; y < height; y++ { img.Set(x, y, color.White) } } for _, elem := range b.elements { if err := b.fillCoordinates(img, elem); err != nil { return err } } f, err := o.Create(fmt.Sprintf("images/%s.png", b.name)) if err != nil { return err } return o.Encode(f, img) }
package components import ( "image/color" "github.com/gowhale/go-circuit-diagram/pkg/common" ) // ConnectionConfig represents two components attached type ConnectionConfig struct { cord common.Coordinate Colour color.Color } // NewConnection returns a ConnectionConfig at specified x,y func NewConnection(cord common.Coordinate) ConnectionConfig { return ConnectionConfig{ cord: cord, Colour: color.Black, } } // GetColour gets the colour to render the element in func (g *ConnectionConfig) GetColour() color.Color { return g.Colour } // GetCoordinates calculates cords to draw onto a canvas func (g *ConnectionConfig) GetCoordinates() ([][]int, error) { cords := [][]int{} cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY()}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY()}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX(), g.cord.GetY() - 1}) cords = append(cords, []int{g.cord.GetX(), g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY() - 1}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY() - 1}) return cords, nil }
package components import ( "image/color" "github.com/gowhale/go-circuit-diagram/pkg/common" ) // GPIOConfig is configuration for a line on the canvas type GPIOConfig struct { cord common.Coordinate Colour color.Color } // NewGPIO returns a GPIO config starting at specified x,y func NewGPIO(cord common.Coordinate) GPIOConfig { return GPIOConfig{ cord: cord, Colour: color.RGBA{0, 255, 0, 0xff}, } } // GetColour gets the colour to render the element in func (g *GPIOConfig) GetColour() color.Color { return g.Colour } // GetCoordinates calculates cords to draw onto a canvas func (g *GPIOConfig) GetCoordinates() ([][]int, error) { cords := [][]int{} cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY()}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY()}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX(), g.cord.GetY()}) cords = append(cords, []int{g.cord.GetX(), g.cord.GetY() - 1}) cords = append(cords, []int{g.cord.GetX(), g.cord.GetY() + 1}) cords = append(cords, []int{g.cord.GetX() - 1, g.cord.GetY() - 1}) cords = append(cords, []int{g.cord.GetX() + 1, g.cord.GetY() - 1}) return cords, nil }
package components import ( "image/color" "github.com/gowhale/go-circuit-diagram/pkg/common" "github.com/gowhale/led-matrix-golang/pkg/matrix" ) // LabelConfig represents two components attached type LabelConfig struct { cord common.Coordinate Colour color.Color text string } // NewLabel returns a LabelConfig at specified x,y func NewLabel(cord common.Coordinate, text string) LabelConfig { return LabelConfig{ cord: cord, Colour: color.Black, text: text, } } // GetColour gets the colour to render the element in func (g *LabelConfig) GetColour() color.Color { return g.Colour } // GetCoordinates calculates cords to draw onto a canvas func (g *LabelConfig) GetCoordinates() ([][]int, error) { cords := [][]int{} pixels, err := matrix.ConcatanateLetters(g.text) if err != nil { return [][]int{}, err } for y := 0; y < len(pixels); y++ { for x := 0; x < len(pixels[y]); x++ { if pixels[y][x] == pixelFill { cords = append(cords, []int{x + g.cord.X - len(pixels[0])/2, y + g.cord.Y - len(pixels)/2}) } } } return cords, nil }
package components import ( "fmt" "image" "image/color" "github.com/gowhale/go-circuit-diagram/pkg/common" ) const ( ledFileName = "images/led.png" // North Direction which the LED can point North = "N" // East Direction which the LED can point East = "E" // South Direction which the LED can point South = "S" // West Direction which the LED can point West = "W" ) var directions = map[string]bool{ North: true, East: true, South: true, West: true, } // LEDConfig is configuration for an LED component type LEDConfig struct { startCoord common.Coordinate LedPixels [][]int Colour color.Color Direction string } func reverse1DSlice(arr []int) { for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 { arr[i], arr[j] = arr[j], arr[i] } } func reverse2DSlice(arr [][]int) { for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 { arr[i], arr[j] = arr[j], arr[i] } } func transformPixels(pixels [][]int, direction string) [][]int { newPixels := make([][]int, len(pixels)) copy(newPixels, pixels) if direction == North { return pixels } if direction == South { reverse2DSlice(newPixels) return newPixels } newPixels = [][]int{} for range pixels[0] { newPixels = append(newPixels, []int{}) } for _, row := range pixels { for k, pixel := range row { newPixels[k] = append(newPixels[k], pixel) } } if direction == West { return newPixels } for _, row := range newPixels { reverse1DSlice(row) } return newPixels } // NewLED returns a LED config starting from specified x,y func NewLED(startCoord common.Coordinate, direction string) (LEDConfig, error) { if _, ok := directions[direction]; !ok { return LEDConfig{}, fmt.Errorf("direction not valid") } return LEDConfig{ startCoord: startCoord, LedPixels: transformPixels(ledPixels, direction), Colour: color.Black, Direction: direction, }, nil } // GetColour gets the colour to render the element in func (l *LEDConfig) GetColour() color.Color { return l.Colour } // GetCoordinates calculates cords to draw onto a canvas func (l *LEDConfig) GetCoordinates() ([][]int, error) { cordsToDraw := [][]int{} for x := range l.LedPixels[0] { for y := range l.LedPixels { if l.LedPixels[y][x] == pixelFill { cordsToDraw = append(cordsToDraw, []int{x + l.startCoord.GetX(), y + l.startCoord.GetY()}) } } } return cordsToDraw, nil } // GetCathode gets the LED's cathode coord func (l *LEDConfig) GetCathode() common.Coordinate { if l.Direction == North { return common.NewCord(l.startCoord.GetX()+5, l.startCoord.GetY()) } if l.Direction == East { return common.NewCord(l.startCoord.GetX()-1, l.startCoord.GetY()+5) } if l.Direction == South { return common.NewCord(l.startCoord.GetX()+5, l.startCoord.GetY()+len(ledPixels)) } return common.NewCord(l.startCoord.GetX()+len(ledPixels), l.startCoord.GetY()+5) } // GetAnode gets the LED's anode coord func (l *LEDConfig) GetAnode() common.Coordinate { if l.Direction == North { return common.NewCord(l.startCoord.GetX()+5, l.startCoord.GetY()+len(ledPixels)) } if l.Direction == East { return common.NewCord(l.startCoord.GetX()+len(ledPixels), l.startCoord.GetY()+5) } if l.Direction == South { return common.NewCord(l.startCoord.GetX()+5, l.startCoord.GetY()) } return common.NewCord(l.startCoord.GetX()-1, l.startCoord.GetY()+5) } func validatePixelArray(pixelArray [][]int) error { width := len(pixelArray[0]) for i, row := range pixelArray { if len(row) != width { return fmt.Errorf("row #%d is not same width as first row #1", i+1) } } return nil } // DrawLED will create pixel art of an LED func DrawLED(o common.OS) error { return drawLEDImpl(o, ledPixels) } func drawLEDImpl(o common.OS, pixelArray [][]int) error { err := validatePixelArray(pixelArray) if err != nil { return err } width := len(pixelArray[0]) height := len(pixelArray) upLeft := image.Point{0, 0} lowRight := image.Point{width, height} img := image.NewRGBA(image.Rectangle{upLeft, lowRight}) // Set color for each pixel. for x := 0; x < width; x++ { for y := 0; y < height; y++ { switch { case pixelArray[y][x] == pixelEmpt: // upper left quadrant img.Set(x, y, color.White) case pixelArray[y][x] == pixelFill: // lower right quadrant img.Set(x, y, color.Black) default: return fmt.Errorf("pixel value not handled") } } } f, err := o.Create(ledFileName) if err != nil { return err } return o.Encode(f, img) }
package components import ( "fmt" "image/color" "github.com/gowhale/go-circuit-diagram/pkg/common" ) // WireConfig is configuration for a line on the canvas type WireConfig struct { startCoord common.Coordinate endCoord common.Coordinate Colour color.Color } // NewWire returns a Wire config starting from specified x,y and ending at x,y // Note: only straight lines currently supported func NewWire(startCoord, endCoord common.Coordinate) WireConfig { return WireConfig{ startCoord: startCoord, endCoord: endCoord, Colour: color.Black, } } // GetColour gets the colour to render the element in func (w *WireConfig) GetColour() color.Color { return w.Colour } func verticalCoords(w *WireConfig) [][]int { lineCords := [][]int{} for y := w.startCoord.GetY(); y < w.endCoord.GetY()+1; y++ { lineCords = append(lineCords, []int{w.startCoord.GetX(), y}) } if len(lineCords) == 0 { for y := w.endCoord.GetY(); y < w.startCoord.GetY()+1; y++ { lineCords = append(lineCords, []int{w.startCoord.GetX(), y}) } } return lineCords } func horizontal(w *WireConfig) [][]int { lineCords := [][]int{} for x := w.startCoord.GetX(); x < w.endCoord.GetX()+1; x++ { lineCords = append(lineCords, []int{x, w.startCoord.GetY()}) } if len(lineCords) == 0 { for x := w.endCoord.GetX(); x < w.startCoord.GetX()+1; x++ { lineCords = append(lineCords, []int{x, w.startCoord.GetY()}) } } return lineCords } // GetCoordinates calculates cords to draw onto a canvas func (w *WireConfig) GetCoordinates() ([][]int, error) { if w.startCoord.GetX() != w.endCoord.GetX() && w.startCoord.GetY() != w.endCoord.GetY() { return [][]int{}, fmt.Errorf("only straight lines, horizontal or vertical") } // vertical line if w.startCoord.GetX() == w.endCoord.GetX() { return verticalCoords(w), nil } // horizontal line return horizontal(w), nil }
package ledmatrix import ( "fmt" "log" "github.com/gowhale/go-circuit-diagram/pkg/canvas" "github.com/gowhale/go-circuit-diagram/pkg/common" "github.com/gowhale/go-circuit-diagram/pkg/components" ) func addLEDS(board *canvas.Board, ledMatrix [][]components.LEDConfig, cols, rows int) { for y := 0; y < rows; y++ { for x := 0; x < cols; x++ { led, err := components.NewLED(common.NewCord(40+(x*30), 40+(y*30)), components.North) if err != nil { log.Fatal(err) } board.AddElement(&led) connection := components.NewConnection(led.GetAnode()) board.AddElement(&connection) ledMatrix[y][x] = led } } } func addVerticalWires(board *canvas.Board, ledMatrix [][]components.LEDConfig, cols, rows int, pins []int) { for i := 0; i < cols; i++ { x := ledMatrix[0][i].GetAnode().X + 15 startY := ledMatrix[0][i].GetAnode().Y - 30 endY := ledMatrix[rows-1][i].GetAnode().Y wire := components.NewWire(common.NewCord(x, startY), common.NewCord(x, endY)) board.AddElement(&wire) label := components.NewLabel(common.NewCord(x, ledMatrix[0][i].GetAnode().Y-40), fmt.Sprintf("%d", pins[i])) board.AddElement(&label) } } func addHorizontalWires(board *canvas.Board, ledMatrix [][]components.LEDConfig, cols, rows int, pins []int) { for i := 0; i < rows; i++ { y := ledMatrix[i][0].GetAnode().Y startX := ledMatrix[i][0].GetAnode().X - 20 endX := ledMatrix[i][cols-1].GetAnode().X wire := components.NewWire(common.NewCord(startX, y), common.NewCord(endX, y)) board.AddElement(&wire) pinAsString := fmt.Sprintf("%d", pins[i]) log.Println(pinAsString) label := components.NewLabel(common.NewCord(startX-10, y), pinAsString) board.AddElement(&label) } } func connectLEDToVerticalWire(board *canvas.Board, ledMatrix [][]components.LEDConfig) { for y := range ledMatrix { for x := range ledMatrix[y] { top := ledMatrix[y][x].GetCathode() topLED := common.NewCord(top.X+15, top.Y) wire := components.NewWire(top, topLED) board.AddElement(&wire) connection := components.NewConnection(topLED) board.AddElement(&connection) } } } func addVerticalGPIOs(board *canvas.Board, ledMatrix [][]components.LEDConfig) { for _, led := range ledMatrix { leftGPIO := common.NewCord(led[0].GetAnode().X-20, led[0].GetAnode().Y) newGPIO := components.NewGPIO(leftGPIO) board.AddElement(&newGPIO) } } func addHorizontalGPIOs(board *canvas.Board, ledMatrix [][]components.LEDConfig) { for _, led := range ledMatrix { leftGPIO := common.NewCord(led[0].GetAnode().X-20, led[0].GetAnode().Y) newGPIO := components.NewGPIO(leftGPIO) board.AddElement(&newGPIO) } } // CreateAnodeMatrix generates an image for an led matrix func CreateAnodeMatrix(o common.OS, rowPins, colPins []int, imageName string) error { board := canvas.NewBoard(imageName, 40+(len(colPins)*30), 40+(len(rowPins)*30), 10) cols := len(colPins) rows := len(rowPins) ledMatrix := make([][]components.LEDConfig, rows) for i := range ledMatrix { ledMatrix[i] = make([]components.LEDConfig, cols) } addLEDS(&board, ledMatrix, cols, rows) connectLEDToVerticalWire(&board, ledMatrix) addHorizontalWires(&board, ledMatrix, cols, rows, rowPins) addVerticalWires(&board, ledMatrix, cols, rows, colPins) addHorizontalGPIOs(&board, ledMatrix) addVerticalGPIOs(&board, ledMatrix) // Render board return board.Draw(o) }