<commit_before>package cli_test

import (
	. "github.com/jwaldrip/odin/cli"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CLI Start", func() {

	var cli *CLI
	var cmd Command
	var didRun bool

	BeforeEach(func() {
		didRun = false
		runFn := func(c Command) {
			cmd = c
			didRun = true
		}
		cli = NewCLI("v1.0.0", "sample description", runFn)
		cli.ErrorHandling = PanicOnError
		cli.Mute()
	})

	Describe("required parameters", func() {

		BeforeEach(func() {
			cli.DefineParams("paramA", "paramB")
		})

		It("should set the parameters by position", func() {
			cli.Start("cmd", "foo", "bar")
			Expect(cmd.Param("paramA").Get()).To(Equal("foo"))
			Expect(cmd.Param("paramB").Get()).To(Equal("bar"))
			Expect(cmd.Params()).To(
				Equal(
					map[string]Value{"paramA": cmd.Param("paramA"), "paramB": cmd.Param("paramB")},
				),
			)
		})

		Context("when a paramter is mising", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd") }).Should(Panic())
			})
		})
	})

	Describe("flags", func() {

		BeforeEach(func() {
			cli.DefineBoolFlag("foo", false, "is foo")
			cli.AliasFlag('o', "foo")
			cli.DefineStringFlag("bar", "", "what bar are you at?")
			cli.AliasFlag('r', "bar")
			cli.DefineBoolFlag("baz", true, "is baz")
			cli.AliasFlag('z', "baz")
		})

		It("should set the flags with set syntax", func() {
			cli.Start("cmd", "--bar=squeaky bean")
			Expect(cmd.Flag("bar").Get()).To(Equal("squeaky bean"))
		})

		It("should set the flags with positional syntax", func() {
			cli.Start("cmd", "--bar", "squeaky bean")
			Expect(cmd.Flag("bar").Get()).To(Equal("squeaky bean"))
		})

		Context("invalid flags", func() {
			It("should panic", func() {
				Ω(func() { cli.Start("cmd", "--invalid") }).Should(Panic())
			})
		})

		Context("boolean flags", func() {

			It("should set boolean flags as true if set", func() {
				cli.Start("cmd", "--foo", "--baz")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("baz").Get()).To(Equal(true))
			})

			It("should set as the default value true if not set", func() {
				cli.Start("cmd")
				Expect(cmd.Flag("foo").Get()).To(Equal(false))
				Expect(cmd.Flag("baz").Get()).To(Equal(true))
			})

			It("should not support positional setting", func() {
				cli.Start("cmd", "--foo", "false")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Args()).To(Equal([]string{"false"}))
			})

		})

		Context("when an invalid flag was passed", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "--bad") }).Should(Panic())
			})
		})

		Context("when a non-boolflag was not provided a value", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "--bar") }).Should(Panic())
			})
		})

		Context("with aliases", func() {

			It("should set the last flag with set syntax", func() {
				cli.Start("cmd", "-or=dive bar")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("bar").Get()).To(Equal("dive bar"))
			})

			It("should set the last flag with positional syntax", func() {
				cli.Start("cmd", "-or", "dive bar")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("bar").Get()).To(Equal("dive bar"))
			})

			Context("when an invalid alias was passed", func() {
				It("should raise an error", func() {
					Ω(func() { cli.Start("cmd", "-op") }).Should(Panic())
				})
			})

			Context("when a non-boolflag was not provided a value", func() {
				It("should raise an error", func() {
					Ω(func() { cli.Start("cmd", "-or") }).Should(Panic())
				})
			})

		})

		Context("once flags are terminated", func() {
			Context("with --", func() {
				It("should not parse additional flags", func() {
					cli.DefineBoolFlag("sample", false, "a sample flag")
					cli.Start("cmd", "--", "--sample=true")
					Expect(cmd.Flag("sample").Get()).To(Equal(false))
					Expect(cmd.Args()).To(Equal([]string{"--sample=true"}))
				})
			})

			Context("with non flag", func() {
				It("should not parse additional flags", func() {
					cli.DefineBoolFlag("sample", false, "a sample flag")
					cli.Start("cmd", "foo", "--sample=true")
					Expect(cmd.Flag("sample").Get()).To(Equal(false))
					Expect(cmd.Args()).To(Equal([]string{"foo", "--sample=true"}))
				})
			})
		})

	})

	Describe("remaining arguments", func() {
		It("should return any arguments that have not been specified", func() {
			cli.Start("cmd", "super", "awesome", "dude")
			Expect(cmd.Args()).To(Equal([]string{"super", "awesome", "dude"}))
			Expect(cmd.Arg(0)).To(Equal("super"))
			Expect(cmd.Arg(1)).To(Equal("awesome"))
			Expect(cmd.Arg(2)).To(Equal("dude"))
		})

		Context("once flags are terminated", func() {
			It("should return what would usually be flag values", func() {
				cli.DefineBoolFlag("sample", false, "a sample flag")
				cli.Start("cmd", "--", "--sample=true")
				Expect(cmd.Flag("sample").Get()).To(Equal(false))
				Expect(cmd.Args()).To(Equal([]string{"--sample=true"}))
			})
		})
	})

	Describe("subcommands", func() {

		var didRunSub bool

		BeforeEach(func() {
			didRunSub = false
			cli.DefineSubCommand("razzle", "razzle dazzle me", func(c Command) {
				didRunSub = true
			})
		})

		Context("when the subcommand is valid", func() {
			It("should start a subcommand", func() {
				cli.Start("cmd", "razzle")
				Expect(didRunSub).To(Equal(true))
			})
		})

		Context("when the subcommand is not valid", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "bad") }).Should(Panic())
			})
		})
	})

})
<commit_msg>test for a complex cli<commit_after>package cli_test

import (
	"strings"

	. "github.com/jwaldrip/odin/cli"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CLI Start", func() {

	var cli *CLI
	var cmd Command
	var didRun bool

	BeforeEach(func() {
		didRun = false
		runFn := func(c Command) {
			cmd = c
			didRun = true
		}
		cli = NewCLI("v1.0.0", "sample description", runFn)
		cli.ErrorHandling = PanicOnError
		cli.Mute()
	})

	Describe("complex cli", func() {

		var subDidRun bool
		var subCmd *SubCommand

		BeforeEach(func() {
			cli.DefineParams("host", "path")
			cli.DefineBoolFlag("ssl", false, "do it over ssl")
			cli.AliasFlag('S', "ssl")
			cli.DefineStringFlag("username", "", "the username")
			cli.AliasFlag('u', "username")
			cli.DefineStringFlag("password", "", "the password")
			cli.AliasFlag('p', "password")
			cli.DefineIntFlag("port", 80, "the port")
			cli.AliasFlag('P', "port")
			subCmd = cli.DefineSubCommand("do", "what action to do", func(c Command) { cmd = c; subDidRun = true }, "action")
		})

		It("should parse the main command properly", func() {
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com /", " ")...)
			Expect(cmd.Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Flag("ssl").Get()).To(Equal(true))
			Expect(didRun).To(Equal(true))
		})

		It("should parse the sub command properly", func() {
			subCmd.DefineBoolFlag("power", false, "with power")
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com / do --power something", " ")...)
			Expect(cmd.Parent().Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Parent().Param("path").Get()).To(Equal("/"))
			Expect(cmd.Parent().Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Parent().Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Parent().Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Parent().Flag("ssl").Get()).To(Equal(true))
			Expect(cmd.Flag("power").Get()).To(Equal(true))
			Expect(cmd.Param("action").Get()).To(Equal("something"))
			Expect(subDidRun).To(Equal(true))
		})

		Describe("version", func() {
			It("should not panic", func() {
				cli.Start("cmd", "--version")
			})
		})

		Describe("help", func() {
			It("should not panic", func() {
				cli.Start(strings.Split("cmd --help", " ")...)
				cli.Start(strings.Split("cmd host path do --help", " ")...)
			})
		})

	})

	Describe("required parameters", func() {

		BeforeEach(func() {
			cli.DefineParams("paramA", "paramB")
		})

		It("should set the parameters by position", func() {
			cli.Start("cmd", "foo", "bar")
			Expect(cmd.Param("paramA").Get()).To(Equal("foo"))
			Expect(cmd.Param("paramB").Get()).To(Equal("bar"))
			Expect(cmd.Params()).To(
				Equal(
					map[string]Value{"paramA": cmd.Param("paramA"), "paramB": cmd.Param("paramB")},
				),
			)
		})

		Context("when a paramter is mising", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd") }).Should(Panic())
			})
		})
	})

	Describe("flags", func() {

		BeforeEach(func() {
			cli.DefineBoolFlag("foo", false, "is foo")
			cli.AliasFlag('o', "foo")
			cli.DefineStringFlag("bar", "", "what bar are you at?")
			cli.AliasFlag('r', "bar")
			cli.DefineBoolFlag("baz", true, "is baz")
			cli.AliasFlag('z', "baz")
		})

		It("should set the flags with set syntax", func() {
			cli.Start("cmd", "--bar=squeaky bean")
			Expect(cmd.Flag("bar").Get()).To(Equal("squeaky bean"))
		})

		It("should set the flags with positional syntax", func() {
			cli.Start("cmd", "--bar", "squeaky bean")
			Expect(cmd.Flag("bar").Get()).To(Equal("squeaky bean"))
		})

		Context("invalid flags", func() {
			It("should panic", func() {
				Ω(func() { cli.Start("cmd", "--invalid") }).Should(Panic())
			})
		})

		Context("boolean flags", func() {

			It("should set boolean flags as true if set", func() {
				cli.Start("cmd", "--foo", "--baz")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("baz").Get()).To(Equal(true))
			})

			It("should set as the default value true if not set", func() {
				cli.Start("cmd")
				Expect(cmd.Flag("foo").Get()).To(Equal(false))
				Expect(cmd.Flag("baz").Get()).To(Equal(true))
			})

			It("should not support positional setting", func() {
				cli.Start("cmd", "--foo", "false")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Args()).To(Equal([]string{"false"}))
			})

		})

		Context("when an invalid flag was passed", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "--bad") }).Should(Panic())
			})
		})

		Context("when a non-boolflag was not provided a value", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "--bar") }).Should(Panic())
			})
		})

		Context("with aliases", func() {

			It("should set the last flag with set syntax", func() {
				cli.Start("cmd", "-or=dive bar")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("bar").Get()).To(Equal("dive bar"))
			})

			It("should set the last flag with positional syntax", func() {
				cli.Start("cmd", "-or", "dive bar")
				Expect(cmd.Flag("foo").Get()).To(Equal(true))
				Expect(cmd.Flag("bar").Get()).To(Equal("dive bar"))
			})

			Context("when an invalid alias was passed", func() {
				It("should raise an error", func() {
					Ω(func() { cli.Start("cmd", "-op") }).Should(Panic())
				})
			})

			Context("when a non-boolflag was not provided a value", func() {
				It("should raise an error", func() {
					Ω(func() { cli.Start("cmd", "-or") }).Should(Panic())
				})
			})

		})

		Context("once flags are terminated", func() {
			Context("with --", func() {
				It("should not parse additional flags", func() {
					cli.DefineBoolFlag("sample", false, "a sample flag")
					cli.Start("cmd", "--", "--sample=true")
					Expect(cmd.Flag("sample").Get()).To(Equal(false))
					Expect(cmd.Args()).To(Equal([]string{"--sample=true"}))
				})
			})

			Context("with non flag", func() {
				It("should not parse additional flags", func() {
					cli.DefineBoolFlag("sample", false, "a sample flag")
					cli.Start("cmd", "foo", "--sample=true")
					Expect(cmd.Flag("sample").Get()).To(Equal(false))
					Expect(cmd.Args()).To(Equal([]string{"foo", "--sample=true"}))
				})
			})
		})

	})

	Describe("remaining arguments", func() {
		It("should return any arguments that have not been specified", func() {
			cli.Start("cmd", "super", "awesome", "dude")
			Expect(cmd.Args()).To(Equal([]string{"super", "awesome", "dude"}))
			Expect(cmd.Arg(0)).To(Equal("super"))
			Expect(cmd.Arg(1)).To(Equal("awesome"))
			Expect(cmd.Arg(2)).To(Equal("dude"))
		})

		Context("once flags are terminated", func() {
			It("should return what would usually be flag values", func() {
				cli.DefineBoolFlag("sample", false, "a sample flag")
				cli.Start("cmd", "--", "--sample=true")
				Expect(cmd.Flag("sample").Get()).To(Equal(false))
				Expect(cmd.Args()).To(Equal([]string{"--sample=true"}))
			})
		})
	})

	Describe("subcommands", func() {

		var didRunSub bool

		BeforeEach(func() {
			didRunSub = false
			cli.DefineSubCommand("razzle", "razzle dazzle me", func(c Command) {
				didRunSub = true
			})
		})

		Context("when the subcommand is valid", func() {
			It("should start a subcommand", func() {
				cli.Start("cmd", "razzle")
				Expect(didRunSub).To(Equal(true))
			})
		})

		Context("when the subcommand is not valid", func() {
			It("should raise an error", func() {
				Ω(func() { cli.Start("cmd", "bad") }).Should(Panic())
			})
		})
	})

})
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net"
	"syscall"
	//"golang.org/x/net/ipv4"
)

type IP_Conn struct {
	fd        int
	version   uint8
	dst, src  string
	headerLen uint16
	//len uint16
	//id uint16
	ttl      uint8
	protocol uint8
	//checksum int
	identifier uint16
}

func NewIP_Conn(dst string) (*IP_Conn, error) {
	//pc, err := net.ListenIP("ip4:17", &net.IPAddr{IP: net.ParseIP(dst)})
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
	if err != nil {
		fmt.Println("Failed to ListenIP")
		return nil, err
	}

	return &IP_Conn{
		fd:         fd,
		version:    4,
		headerLen:  20,
		dst:        dst,
		src:        "127.0.0.1",
		ttl:        8,
		protocol:   17,
		identifier: 20000,
	}, nil
}

func calcChecksum(head []byte, excludeChecksum bool) uint16 {
	totalSum := uint64(0)
	for ind, elem := range head {
		if (ind == 10 || ind == 11) && excludeChecksum { // Ignore the checksum in some situations
			continue
		}

		if ind%2 == 0 {
			totalSum += (uint64(elem) << 8)
		} else {
			totalSum += uint64(elem)
		}
	}
	fmt.Println("Checksum total: ", totalSum)

	for prefix := (totalSum >> 16); prefix != 0; prefix = (totalSum >> 16) {
		//        fmt.Println(prefix)
		//        fmt.Println(totalSum)
		//        fmt.Println(totalSum & 0xffff)
		totalSum = uint64(totalSum&0xffff) + prefix
	}
	fmt.Println("Checksum after carry: ", totalSum)

	carried := uint16(totalSum)

	return ^carried
}

func slicePacket(b []byte) (hrd, payload []byte) {
	hdrLen := int(b[0]&0x0f) * 4
	fmt.Println("HdrLen: ", hdrLen)
	return b[:hdrLen], b[hdrLen:]
}

func (ipc *IP_Conn) ReadFrom(b []byte) (payload []byte, e error) {
	n, _, err := syscall.Recvfrom(ipc.fd, b, 0) //_ is src address
	b = b[:n]
	fmt.Println("Read Length: ", n)
	fmt.Println("Full Read Data (after trim): ", b)
	hdr, p := slicePacket(b)

	// verify checksum
	if calcChecksum(hdr, false) != 0 {
		fmt.Println("Header checksum verification failed. Packet dropped.")
		fmt.Println("Wrong header: ", hdr)
		fmt.Println("Payload (dropped): ", p)
		return nil, errors.New("Header checksum incorrect, packet dropped")
	}

	return p, err
}

func (ipc *IP_Conn) WriteTo(p []byte) error {
	totalLen := uint16(ipc.headerLen) + uint16(len(p))
	fmt.Println("Total Len: ", totalLen)
	packet := make([]byte, ipc.headerLen)
	packet[0] = (byte)((ipc.version << 4) + (uint8)(ipc.headerLen/4)) // Version, IHL
	packet[1] = 0
	packet[2] = (byte)(totalLen >> 8) // Total Len
	packet[3] = (byte)(totalLen)

	id := ipc.identifier
	packet[4] = byte(id >> 8) // Identification
	packet[5] = byte(id)
	ipc.identifier++

	packet[6] = byte(1 << 6)         // Flags: Don't fragment
	packet[7] = 0                    // Fragment Offset
	packet[8] = (byte)(ipc.ttl)      // Time to Live
	packet[9] = (byte)(ipc.protocol) // Protocol

	// Src and Dst IPs
	srcIP := net.ParseIP(ipc.src)
	fmt.Println(srcIP)
	//    fmt.Println(srcIP[12])
	//    fmt.Println(srcIP[13])
	//    fmt.Println(srcIP[14])
	//    fmt.Println(srcIP[15])
	dstIP := net.ParseIP(ipc.dst)
	fmt.Println(dstIP)
	packet[12] = srcIP[12]
	packet[13] = srcIP[13]
	packet[14] = srcIP[14]
	packet[15] = srcIP[15]
	packet[16] = dstIP[12]
	packet[17] = dstIP[13]
	packet[18] = dstIP[14]
	packet[19] = dstIP[15]

	// IPv4 header test (before checksum)
	fmt.Println("Packet before checksum: ", packet)

	// Checksum
	checksum := calcChecksum(packet[:20], true)
	packet[10] = byte(checksum >> 8)
	packet[11] = byte(checksum)

	// Payload
	packet = append(packet, p...)
	fmt.Println("Full Packet:  ", packet)

	dstIPAddr, err := net.ResolveIPAddr("ip", ipc.dst)
	if err != nil {
		//        fmt.Println(err)
		return err
	}
	fmt.Println("Full Address: ", dstIPAddr)

	//ipc.pc.WriteMsgIP(packet, nil, dstIPAddr)

	addr := syscall.SockaddrInet4{
		Port: 0,
		//Addr: [4]byte{127, 0, 0, 1},
		Addr: [4]byte{
			dstIPAddr.IP[12],
			dstIPAddr.IP[13],
			dstIPAddr.IP[14],
			dstIPAddr.IP[15],
		},
	}
	syscall.Sendto(ipc.fd, packet, 0, &addr)
	return err
}

func (ipc *IP_Conn) Close() error {
	return syscall.Close(ipc.fd)
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<commit_msg>Using bind to connect to the port<commit_after>package main

import (
	"errors"
	"fmt"
	"net"
	"syscall"
	//"golang.org/x/net/ipv4"
)

type IP_Conn struct {
	fd        int
    sockAddr  syscall.Sockaddr
	version   uint8
	dst, src  string
	headerLen uint16
	//len uint16
	//id uint16
	ttl      uint8
	protocol uint8
	//checksum int
	identifier uint16
}

func NewIP_Conn(dst string) (*IP_Conn, error) {
	//pc, err := net.ListenIP("ip4:17", &net.IPAddr{IP: net.ParseIP(dst)})
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
	if err != nil {
		fmt.Println("Failed to ListenIP")
		return nil, err
	}

    dstIPAddr, err := net.ResolveIPAddr("ip", dst)
    if err != nil {
        //fmt.Println(err)
        return nil, err
    }
    fmt.Println("Full Address: ", dstIPAddr)

    addr := &syscall.SockaddrInet4{
        Port: 0,
        //Addr: [4]byte{127, 0, 0, 1},
        Addr: [4]byte{
            dstIPAddr.IP[12],
            dstIPAddr.IP[13],
            dstIPAddr.IP[14],
            dstIPAddr.IP[15],
        },
    }

    err = syscall.Bind(fd, addr)
    if err != nil {
        return nil, errors.New("Failed to bind to address.")
    }

	return &IP_Conn{
		fd:         fd,
        sockAddr:   addr,
		version:    4,
		headerLen:  20,
		dst:        dst,
		src:        "127.0.0.1",
		ttl:        8,
		protocol:   17,
		identifier: 20000,
	}, nil
}

func calcChecksum(head []byte, excludeChecksum bool) uint16 {
	totalSum := uint64(0)
	for ind, elem := range head {
		if (ind == 10 || ind == 11) && excludeChecksum { // Ignore the checksum in some situations
			continue
		}

		if ind%2 == 0 {
			totalSum += (uint64(elem) << 8)
		} else {
			totalSum += uint64(elem)
		}
	}
	fmt.Println("Checksum total: ", totalSum)

	for prefix := (totalSum >> 16); prefix != 0; prefix = (totalSum >> 16) {
		//        fmt.Println(prefix)
		//        fmt.Println(totalSum)
		//        fmt.Println(totalSum & 0xffff)
		totalSum = uint64(totalSum&0xffff) + prefix
	}
	fmt.Println("Checksum after carry: ", totalSum)

	carried := uint16(totalSum)

	return ^carried
}

func slicePacket(b []byte) (hrd, payload []byte) {
	hdrLen := int(b[0]&0x0f) * 4
	fmt.Println("HdrLen: ", hdrLen)
	return b[:hdrLen], b[hdrLen:]
}

func (ipc *IP_Conn) ReadFrom(b []byte) (payload []byte, e error) {
	n, _, err := syscall.Recvfrom(ipc.fd, b, 0) //_ is src address
	b = b[:n]
	fmt.Println("Read Length: ", n)
	fmt.Println("Full Read Data (after trim): ", b)
	hdr, p := slicePacket(b)

	// verify checksum
	if calcChecksum(hdr, false) != 0 {
		fmt.Println("Header checksum verification failed. Packet dropped.")
		fmt.Println("Wrong header: ", hdr)
		fmt.Println("Payload (dropped): ", p)
		return nil, errors.New("Header checksum incorrect, packet dropped")
	}

	return p, err
}

func (ipc *IP_Conn) WriteTo(p []byte) error {
	totalLen := uint16(ipc.headerLen) + uint16(len(p))
	fmt.Println("Total Len: ", totalLen)
	packet := make([]byte, ipc.headerLen)
	packet[0] = (byte)((ipc.version << 4) + (uint8)(ipc.headerLen/4)) // Version, IHL
	packet[1] = 0
	packet[2] = (byte)(totalLen >> 8) // Total Len
	packet[3] = (byte)(totalLen)

	id := ipc.identifier
	packet[4] = byte(id >> 8) // Identification
	packet[5] = byte(id)
	ipc.identifier++

	packet[6] = byte(1 << 6)         // Flags: Don't fragment
	packet[7] = 0                    // Fragment Offset
	packet[8] = (byte)(ipc.ttl)      // Time to Live
	packet[9] = (byte)(ipc.protocol) // Protocol

	// Src and Dst IPs
	srcIP := net.ParseIP(ipc.src)
	fmt.Println(srcIP)
	//    fmt.Println(srcIP[12])
	//    fmt.Println(srcIP[13])
	//    fmt.Println(srcIP[14])
	//    fmt.Println(srcIP[15])
	dstIP := net.ParseIP(ipc.dst)
	fmt.Println(dstIP)
	packet[12] = srcIP[12]
	packet[13] = srcIP[13]
	packet[14] = srcIP[14]
	packet[15] = srcIP[15]
	packet[16] = dstIP[12]
	packet[17] = dstIP[13]
	packet[18] = dstIP[14]
	packet[19] = dstIP[15]

	// IPv4 header test (before checksum)
	fmt.Println("Packet before checksum: ", packet)

	// Checksum
	checksum := calcChecksum(packet[:20], true)
	packet[10] = byte(checksum >> 8)
	packet[11] = byte(checksum)

	// Payload
	packet = append(packet, p...)
	fmt.Println("Full Packet:  ", packet)

	//ipc.pc.WriteMsgIP(packet, nil, dstIPAddr)

	return syscall.Sendto(ipc.fd, packet, 0, ipc.sockAddr)
}

func (ipc *IP_Conn) Close() error {
	return syscall.Close(ipc.fd)
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<|endoftext|>


<commit_before>package bwhatsapp

import (
	"fmt"
	"mime"
	"strings"
	"time"

	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/helper"
	"github.com/Rhymen/go-whatsapp"
	"github.com/jpillora/backoff"
)

/*
Implement handling messages coming from WhatsApp
Check:
- https://github.com/Rhymen/go-whatsapp#add-message-handlers
- https://github.com/Rhymen/go-whatsapp/blob/master/handler.go
- https://github.com/tulir/mautrix-whatsapp/tree/master/whatsapp-ext for more advanced command handling
*/

// HandleError received from WhatsApp
func (b *Bwhatsapp) HandleError(err error) {
	// ignore received invalid data errors. https://github.com/42wim/matterbridge/issues/843
	// ignore tag 174 errors. https://github.com/42wim/matterbridge/issues/1094
	if strings.Contains(err.Error(), "error processing data: received invalid data") ||
		strings.Contains(err.Error(), "invalid string with tag 174") {
		return
	}

	switch err.(type) {
	case *whatsapp.ErrConnectionClosed, *whatsapp.ErrConnectionFailed:
		b.reconnect(err)
	default:
		switch err {
		case whatsapp.ErrConnectionTimeout:
			b.reconnect(err)
		default:
			b.Log.Errorf("%v", err)
		}
	}
}

func (b *Bwhatsapp) reconnect(err error) {
	bf := &backoff.Backoff{
		Min:    time.Second,
		Max:    5 * time.Minute,
		Jitter: true,
	}

	for {
		d := bf.Duration()

		b.Log.Errorf("Connection failed, underlying error: %v", err)
		b.Log.Infof("Waiting %s...", d)

		time.Sleep(d)

		b.Log.Info("Reconnecting...")

		err := b.conn.Restore()
		if err == nil {
			bf.Reset()
			b.startedAt = uint64(time.Now().Unix())

			return
		}
	}
}

// HandleTextMessage sent from WhatsApp, relay it to the brige
func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
	if message.Info.FromMe {
		return
	}
	// whatsapp sends last messages to show context , cut them
	if message.Info.Timestamp < b.startedAt {
		return
	}

	groupJID := message.Info.RemoteJid
	senderJID := message.Info.SenderJid

	if len(senderJID) == 0 {
		if message.Info.Source != nil && message.Info.Source.Participant != nil {
			senderJID = *message.Info.Source.Participant
		}
	}

	// translate sender's JID to the nicest username we can get
	senderName := b.getSenderName(senderJID)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	extText := message.Info.Source.Message.ExtendedTextMessage
	if extText != nil && extText.ContextInfo != nil && extText.ContextInfo.MentionedJid != nil {
		// handle user mentions
		for _, mentionedJID := range extText.ContextInfo.MentionedJid {
			numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)

			// mentions comes as telephone numbers and we don't want to expose it to other bridges
			// replace it with something more meaninful to others
			mention := b.getSenderNotify(numberAndSuffix[0] + "@s.whatsapp.net")
			if mention == "" {
				mention = "someone"
			}

			message.Text = strings.Replace(message.Text, "@"+numberAndSuffix[0], "@"+mention, 1)
		}
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Text:     message.Text,
		Channel:  groupJID,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		//	ParentID: TODO, // TODO handle thread replies  // map from Info.QuotedMessageID string
		ID: message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleImageMessage sent from WhatsApp, relay it to the brige
func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with type %s", filename, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download image failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, message.Caption, "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleVideoMessage downloads video messages
func (b *Bwhatsapp) HandleVideoMessage(message whatsapp.VideoMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, message.Length, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download video failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, message.Caption, "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleAudioMessage downloads audio messages
func (b *Bwhatsapp) HandleAudioMessage(message whatsapp.AudioMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, message.Length, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download audio failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, "audio message", "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}
<commit_msg>Rename jfif to jpg (whatsapp). Fixes #1292<commit_after>package bwhatsapp

import (
	"fmt"
	"mime"
	"strings"
	"time"

	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/helper"
	"github.com/Rhymen/go-whatsapp"
	"github.com/jpillora/backoff"
)

/*
Implement handling messages coming from WhatsApp
Check:
- https://github.com/Rhymen/go-whatsapp#add-message-handlers
- https://github.com/Rhymen/go-whatsapp/blob/master/handler.go
- https://github.com/tulir/mautrix-whatsapp/tree/master/whatsapp-ext for more advanced command handling
*/

// HandleError received from WhatsApp
func (b *Bwhatsapp) HandleError(err error) {
	// ignore received invalid data errors. https://github.com/42wim/matterbridge/issues/843
	// ignore tag 174 errors. https://github.com/42wim/matterbridge/issues/1094
	if strings.Contains(err.Error(), "error processing data: received invalid data") ||
		strings.Contains(err.Error(), "invalid string with tag 174") {
		return
	}

	switch err.(type) {
	case *whatsapp.ErrConnectionClosed, *whatsapp.ErrConnectionFailed:
		b.reconnect(err)
	default:
		switch err {
		case whatsapp.ErrConnectionTimeout:
			b.reconnect(err)
		default:
			b.Log.Errorf("%v", err)
		}
	}
}

func (b *Bwhatsapp) reconnect(err error) {
	bf := &backoff.Backoff{
		Min:    time.Second,
		Max:    5 * time.Minute,
		Jitter: true,
	}

	for {
		d := bf.Duration()

		b.Log.Errorf("Connection failed, underlying error: %v", err)
		b.Log.Infof("Waiting %s...", d)

		time.Sleep(d)

		b.Log.Info("Reconnecting...")

		err := b.conn.Restore()
		if err == nil {
			bf.Reset()
			b.startedAt = uint64(time.Now().Unix())

			return
		}
	}
}

// HandleTextMessage sent from WhatsApp, relay it to the brige
func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
	if message.Info.FromMe {
		return
	}
	// whatsapp sends last messages to show context , cut them
	if message.Info.Timestamp < b.startedAt {
		return
	}

	groupJID := message.Info.RemoteJid
	senderJID := message.Info.SenderJid

	if len(senderJID) == 0 {
		if message.Info.Source != nil && message.Info.Source.Participant != nil {
			senderJID = *message.Info.Source.Participant
		}
	}

	// translate sender's JID to the nicest username we can get
	senderName := b.getSenderName(senderJID)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	extText := message.Info.Source.Message.ExtendedTextMessage
	if extText != nil && extText.ContextInfo != nil && extText.ContextInfo.MentionedJid != nil {
		// handle user mentions
		for _, mentionedJID := range extText.ContextInfo.MentionedJid {
			numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)

			// mentions comes as telephone numbers and we don't want to expose it to other bridges
			// replace it with something more meaninful to others
			mention := b.getSenderNotify(numberAndSuffix[0] + "@s.whatsapp.net")
			if mention == "" {
				mention = "someone"
			}

			message.Text = strings.Replace(message.Text, "@"+numberAndSuffix[0], "@"+mention, 1)
		}
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Text:     message.Text,
		Channel:  groupJID,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		//	ParentID: TODO, // TODO handle thread replies  // map from Info.QuotedMessageID string
		ID: message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleImageMessage sent from WhatsApp, relay it to the brige
func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	// rename .jfif to .jpg https://github.com/42wim/matterbridge/issues/1292
	if fileExt[0] == ".jfif" {
		fileExt[0] = ".jpg"
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with type %s", filename, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download image failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, message.Caption, "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleVideoMessage downloads video messages
func (b *Bwhatsapp) HandleVideoMessage(message whatsapp.VideoMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, message.Length, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download video failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, message.Caption, "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}

// HandleAudioMessage downloads audio messages
func (b *Bwhatsapp) HandleAudioMessage(message whatsapp.AudioMessage) {
	if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
		return
	}

	senderJID := message.Info.SenderJid
	if len(message.Info.SenderJid) == 0 && message.Info.Source != nil && message.Info.Source.Participant != nil {
		senderJID = *message.Info.Source.Participant
	}

	senderName := b.getSenderName(message.Info.SenderJid)
	if senderName == "" {
		senderName = "Someone" // don't expose telephone number
	}

	rmsg := config.Message{
		UserID:   senderJID,
		Username: senderName,
		Channel:  message.Info.RemoteJid,
		Account:  b.Account,
		Protocol: b.Protocol,
		Extra:    make(map[string][]interface{}),
		ID:       message.Info.Id,
	}

	if avatarURL, exists := b.userAvatars[senderJID]; exists {
		rmsg.Avatar = avatarURL
	}

	fileExt, err := mime.ExtensionsByType(message.Type)
	if err != nil {
		b.Log.Errorf("Mimetype detection error: %s", err)

		return
	}

	filename := fmt.Sprintf("%v%v", message.Info.Id, fileExt[0])

	b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, message.Length, message.Type)

	data, err := message.Download()
	if err != nil {
		b.Log.Errorf("Download audio failed: %s", err)

		return
	}

	// Move file to bridge storage
	helper.HandleDownloadData(b.Log, &rmsg, filename, "audio message", "", &data, b.General)

	b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
	b.Log.Debugf("<= Message is %#v", rmsg)

	b.Remote <- rmsg
}
<|endoftext|>


<commit_before>package xform

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/xdom"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

func init() {
	style.Add(`label {
	display : block;
	float : left;
	text-align : right;
	width : 200px;
}

label:after {
	content : ':';
}

.sizeableInput {` + dom.GetWindow().Document().(dom.HTMLDocument).DefaultView().GetComputedStyle(xdom.Input(), "").String() + `}
`)
}

func InputSizeable(id, value string) *dom.HTMLSpanElement {
	s := xdom.Span()
	s.Class().SetString("sizeableInput")
	if id != "" {
		s.SetID(id)
	}
	xjs.SetInnerText(s, value)
	return s
}

type SizeableList struct {
	*dom.HTMLDivElement
	contents []*dom.HTMLSpanElement
}

func InputSizeableList(values ...string) *SizeableList {
	d := xdom.Div()
	d.Class().SetString("sizeableList")
	contents := make([]*dom.HTMLSpanElement, len(values))
	for i, value := range values {
		s := InputSizeable("", value)
		d.AppendChild(s)
		contents[i] = s
	}
	sl := &SizeableList{
		d,
		contents,
	}
	remove := xdom.Button()
	remove.Value = "-"
	remove.AddEventListener("click", false, func(dom.Event) {
		l := len(sl.contents) - 1
		d.RemoveChild(sl.contents[l])
		sl.contents = sl.contents[:l]
	})
	add := xdom.Button()
	add.Value = "+"
	add.AddEventListener("click", false, func(dom.Event) {
		s := InputSizeable("", "")
		d.InsertBefore(s, remove)
		sl.contents = append(sl.contents, s)
	})
	d.AppendChild(remove)
	d.AppendChild(add)
	return sl
}

func (s *SizeableList) Values() []string {
	v := make([]string, len(s.contents))
	for i, s := range s.contents {
		v[i] = s.TextContent()
	}
	return v
}

func Label(label, forID string) *dom.HTMLLabelElement {
	l := xdom.Label()
	l.For = forID
	xjs.SetInnerText(l, label)
	return l
}

func InputText(id, value string) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "text"
	if id != "" {
		i.SetID(id)
	}
	i.Value = value
	return i
}

func InputCheckbox(id string, value bool) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "checkbox"
	if id != "" {
		i.SetID(id)
	}
	i.Checked = value
	return i
}

func InputRadio(id, name string, value bool) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "radio"
	i.Name = name
	if id != "" {
		i.SetID(id)
	}
	i.Checked = value
	return i
}

func InputUpload(id string) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "file"
	return i
}

type Option struct {
	Label, Value string
}

func SelectBox(id string, values ...Option) *dom.HTMLSelectElement {
	s := xdom.Select()
	if id != "" {
		s.SetID(id)
	}
	for _, v := range values {
		o := xdom.Option()
		o.Value = v.Value
		s.AppendChild(xjs.SetInnerText(o, v.Label))
	}
	return s
}

func TextArea(id string, value string) *dom.HTMLTextAreaElement {
	t := xdom.Textarea()
	if id != "" {
		t.SetID(id)
	}
	xjs.SetInnerText(t, value)
	return t
}
<commit_msg>Added InputSubmit<commit_after>package xform

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/xdom"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

func init() {
	style.Add(`label {
	display : block;
	float : left;
	text-align : right;
	width : 200px;
}

label:after {
	content : ':';
}

.sizeableInput {` + dom.GetWindow().Document().(dom.HTMLDocument).DefaultView().GetComputedStyle(xdom.Input(), "").String() + `}
`)
}

func InputSizeable(id, value string) *dom.HTMLSpanElement {
	s := xdom.Span()
	s.Class().SetString("sizeableInput")
	if id != "" {
		s.SetID(id)
	}
	xjs.SetInnerText(s, value)
	return s
}

type SizeableList struct {
	*dom.HTMLDivElement
	contents []*dom.HTMLSpanElement
}

func InputSizeableList(values ...string) *SizeableList {
	d := xdom.Div()
	d.Class().SetString("sizeableList")
	contents := make([]*dom.HTMLSpanElement, len(values))
	for i, value := range values {
		s := InputSizeable("", value)
		d.AppendChild(s)
		contents[i] = s
	}
	sl := &SizeableList{
		d,
		contents,
	}
	remove := xdom.Button()
	remove.Value = "-"
	remove.AddEventListener("click", false, func(dom.Event) {
		l := len(sl.contents) - 1
		d.RemoveChild(sl.contents[l])
		sl.contents = sl.contents[:l]
	})
	add := xdom.Button()
	add.Value = "+"
	add.AddEventListener("click", false, func(dom.Event) {
		s := InputSizeable("", "")
		d.InsertBefore(s, remove)
		sl.contents = append(sl.contents, s)
	})
	d.AppendChild(remove)
	d.AppendChild(add)
	return sl
}

func (s *SizeableList) Values() []string {
	v := make([]string, len(s.contents))
	for i, s := range s.contents {
		v[i] = s.TextContent()
	}
	return v
}

func Label(label, forID string) *dom.HTMLLabelElement {
	l := xdom.Label()
	l.For = forID
	xjs.SetInnerText(l, label)
	return l
}

func InputText(id, value string) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "text"
	if id != "" {
		i.SetID(id)
	}
	i.Value = value
	return i
}

func InputCheckbox(id string, value bool) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "checkbox"
	if id != "" {
		i.SetID(id)
	}
	i.Checked = value
	return i
}

func InputRadio(id, name string, value bool) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "radio"
	i.Name = name
	if id != "" {
		i.SetID(id)
	}
	i.Checked = value
	return i
}

func InputUpload(id string) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "file"
	return i
}

func InputSubmit(name string) *dom.HTMLInputElement {
	i := xdom.Input()
	i.Type = "submit"
	i.Value = name
	return i
}

type Option struct {
	Label, Value string
}

func SelectBox(id string, values ...Option) *dom.HTMLSelectElement {
	s := xdom.Select()
	if id != "" {
		s.SetID(id)
	}
	for _, v := range values {
		o := xdom.Option()
		o.Value = v.Value
		s.AppendChild(xjs.SetInnerText(o, v.Label))
	}
	return s
}

func TextArea(id string, value string) *dom.HTMLTextAreaElement {
	t := xdom.Textarea()
	if id != "" {
		t.SetID(id)
	}
	xjs.SetInnerText(t, value)
	return t
}
<|endoftext|>


<commit_before>package xxtea

import (
	"bytes"
	"testing"
)

func TestTransform(t *testing.T) {
	b := [...]byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0}
	u := [...]uint32{1, 2, 3, 4, 5}

	if g := uint32ToBytes(u[:]); bytes.Compare(g, b[:]) != 0 {
		t.Errorf("convertion []uint -> []byte failed:: %+v", g)
	}

	if g := bytesToUint32(b[:]); len(g) != len(u) {
		t.Errorf("convertion []byte -> []uint failed:: %+v", g)
	} else {
		for i, _ := range g {
			if g[i] != u[i] {
				t.Errorf("convertion []byte -> []uint failed:: %+v", g)
				break
			}
		}
	}
}
<commit_msg>simple golint fixes<commit_after>package xxtea

import (
	"bytes"
	"testing"
)

func TestTransform(t *testing.T) {
	b := [...]byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0}
	u := [...]uint32{1, 2, 3, 4, 5}

	if g := uint32ToBytes(u[:]); bytes.Compare(g, b[:]) != 0 {
		t.Errorf("convertion []uint -> []byte failed:: %+v", g)
	}

	if g := bytesToUint32(b[:]); len(g) != len(u) {
		t.Errorf("convertion []byte -> []uint failed:: %+v", g)
	} else {
		for i := range g {
			if g[i] != u[i] {
				t.Errorf("convertion []byte -> []uint failed:: %+v", g)
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package xurls

import (
	"regexp"
	"testing"
)

type regexTestCase struct {
	in   string
	want interface{}
}

var alwaysNegative = []regexTestCase{
	{``, nil},
	{` `, nil},
	{`:`, nil},
	{`::`, nil},
	{`:::`, nil},
	{`::::`, nil},
	{`.`, nil},
	{`..`, nil},
	{`...`, nil},
	{`://`, nil},
	{`foo`, nil},
	{`foo:`, nil},
	{`foo://`, nil},
	{`:foo`, nil},
	{`://foo`, nil},
	{`foo:bar`, nil},
	{`zzz.`, nil},
	{`.zzz`, nil},
	{`zzz.zzz`, nil},
	{`/some/path`, nil},
}

var alwaysPositive = []regexTestCase{
	// Urls with scheme and ://
	{`http://foo.com`, `http://foo.com`},
	{`http://foo.random`, `http://foo.random`},
	{` http://foo.com/bar `, `http://foo.com/bar`},
	{` http://foo.com/bar more`, `http://foo.com/bar`},
	{`<http://foo.com/bar>`, `http://foo.com/bar`},
	{`<http://foo.com/bar>more`, `http://foo.com/bar`},
	{`,http://foo.com/bar.`, `http://foo.com/bar`},
	{`,http://foo.com/bar.more`, `http://foo.com/bar.more`},
	{`,http://foo.com/bar,`, `http://foo.com/bar`},
	{`,http://foo.com/bar,more`, `http://foo.com/bar,more`},
	{`(http://foo.com/bar)`, `http://foo.com/bar`},
	{`(http://foo.com/bar)more`, `http://foo.com/bar)more`},
	{`"http://foo.com/bar'`, `http://foo.com/bar`},
	{`"http://foo.com/bar'more`, `http://foo.com/bar'more`},
	{`"http://foo.com/bar"`, `http://foo.com/bar`},
	{`"http://foo.com/bar"more`, `http://foo.com/bar"more`},
	{`http://a.b/a.,:;-+_()?@&=$~!*%'"a`, `http://a.b/a.,:;-+_()?@&=$~!*%'"a`},
	{`http://foo.com/path_(more)`, `http://foo.com/path_(more)`},
	{`http://test.foo.com/`, `http://test.foo.com/`},
	{`http://foo.com/path`, `http://foo.com/path`},
	{`http://foo.com:8080/path`, `http://foo.com:8080/path`},
	{`http://1.1.1.1/path`, `http://1.1.1.1/path`},
	{`http://1080::8:800:200c:417a/path`, `http://1080::8:800:200c:417a/path`},
	{`what is http://foo.com?`, `http://foo.com`},
	{`the http://foo.com!`, `http://foo.com`},
	{`https://test.foo.bar/path?a=b`, `https://test.foo.bar/path?a=b`},
	{`ftp://user@foo.bar`, `ftp://user@foo.bar`},
}

func doTest(t *testing.T, re *regexp.Regexp, cases []regexTestCase) {
	for _, c := range cases {
		got := re.FindString(c.in)
		var want string
		switch x := c.want.(type) {
		case string:
			want = x
		}
		if got != want {
			t.Errorf(`xurls.All.FindString("%s") got "%s", want "%s"`, c.in, got, want)
		}
	}
}

func TestAll(t *testing.T) {
	doTest(t, All, alwaysNegative)
	doTest(t, All, alwaysPositive)
	doTest(t, All, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, `foo.com`},
		{`foo.com bar.com`, `foo.com`},
		{`foo.com-foo`, `foo.com`},
		{`foo.onion`, `foo.onion`},
		{`foo.i2p`, `foo.i2p`},
		{`中国.中国`, `中国.中国`},
		{`中国.中国/foo中国`, `中国.中国/foo中国`},
		{`foo.com/`, `foo.com/`},
		{`1.1.1.1`, `1.1.1.1`},
		{`121.1.1.1`, `121.1.1.1`},
		{`255.1.1.1`, `255.1.1.1`},
		{`300.1.1.1`, nil},
		{`1.1.1`, nil},
		{`1.1..1`, nil},
		{`1080:0:0:0:8:800:200C:4171`, `1080:0:0:0:8:800:200C:4171`},
		{`3ffe:2a00:100:7031::1`, `3ffe:2a00:100:7031::1`},
		{`1080::8:800:200c:417a`, `1080::8:800:200c:417a`},
		{`1:1`, nil},
		{`:2:`, nil},
		{`1:2:3`, nil},
		{`foo.com:8080`, `foo.com:8080`},
		{`foo.com:8080/path`, `foo.com:8080/path`},
		{`test.foo.com`, `test.foo.com`},
		{`test.foo.com/path`, `test.foo.com/path`},
		{`test.foo.com/path/more/`, `test.foo.com/path/more/`},
		{`TEST.FOO.COM/PATH`, `TEST.FOO.COM/PATH`},
		{`foo.com/a.,:;-+_()?@&=$~!*%'"a`, `foo.com/a.,:;-+_()?@&=$~!*%'"a`},
		{`foo.com/path_(more)`, `foo.com/path_(more)`},
		{`foo.com/path_(even)_(more)`, `foo.com/path_(even)_(more)`},
		{`foo.com/path_(more)/more`, `foo.com/path_(more)/more`},
		{`foo.com/path_(more)/end)`, `foo.com/path_(more)/end)`},
		{`www.foo.com`, `www.foo.com`},
		{` foo.com/bar `, `foo.com/bar`},
		{` foo.com/bar more`, `foo.com/bar`},
		{`<foo.com/bar>`, `foo.com/bar`},
		{`<foo.com/bar>more`, `foo.com/bar`},
		{`,foo.com/bar.`, `foo.com/bar`},
		{`,foo.com/bar.more`, `foo.com/bar.more`},
		{`,foo.com/bar,`, `foo.com/bar`},
		{`,foo.com/bar,more`, `foo.com/bar,more`},
		{`(foo.com/bar)`, `foo.com/bar`},
		{`(foo.com/bar)more`, `foo.com/bar)more`},
		{`"foo.com/bar'`, `foo.com/bar`},
		{`"foo.com/bar'more`, `foo.com/bar'more`},
		{`"foo.com/bar"`, `foo.com/bar`},
		{`"foo.com/bar"more`, `foo.com/bar"more`},
		{`what is foo.com?`, `foo.com`},
		{`the foo.com!`, `foo.com`},

		{`foo@bar`, nil},
		{`foo@bar.a`, nil},
		{`foo@bar.com`, `foo@bar.com`},
		{`foo@bar.com bar@bar.com`, `foo@bar.com`},
		{`foo@bar.onion`, `foo@bar.onion`},
		{`foo@中国.中国`, `foo@中国.中国`},
		{`mailto:foo@bar.com`, `foo@bar.com`},
		{`foo@test.bar.com`, `foo@test.bar.com`},
		{`FOO@TEST.BAR.COM`, `FOO@TEST.BAR.COM`},
		{`foo@bar.com/path`, `foo@bar.com`},
		{`foo+test@bar.com`, `foo+test@bar.com`},
		{`foo+._%-@bar.com`, `foo+._%-@bar.com`},
	})
}

func TestAllStrict(t *testing.T) {
	doTest(t, AllStrict, alwaysNegative)
	doTest(t, AllStrict, alwaysPositive)
	doTest(t, AllStrict, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, nil},
		{`foo.com/`, nil},
		{`1.1.1.1`, nil},
		{`3ffe:2a00:100:7031::1`, nil},
		{`test.foo.com:8080/path`, nil},
		{`foo@bar.com`, nil},
	})
}
<commit_msg>Move some tests to alwaysNegative<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package xurls

import (
	"regexp"
	"testing"
)

type regexTestCase struct {
	in   string
	want interface{}
}

var alwaysNegative = []regexTestCase{
	{``, nil},
	{` `, nil},
	{`:`, nil},
	{`::`, nil},
	{`:::`, nil},
	{`::::`, nil},
	{`.`, nil},
	{`..`, nil},
	{`...`, nil},
	{`1.1`, nil},
	{`.1.`, nil},
	{`1.1.1`, nil},
	{`1:1`, nil},
	{`:1:`, nil},
	{`1:1:1`, nil},
	{`://`, nil},
	{`foo`, nil},
	{`foo:`, nil},
	{`foo://`, nil},
	{`:foo`, nil},
	{`://foo`, nil},
	{`foo:bar`, nil},
	{`zzz.`, nil},
	{`.zzz`, nil},
	{`zzz.zzz`, nil},
	{`/some/path`, nil},
}

var alwaysPositive = []regexTestCase{
	// Urls with scheme and ://
	{`http://foo.com`, `http://foo.com`},
	{`http://foo.random`, `http://foo.random`},
	{` http://foo.com/bar `, `http://foo.com/bar`},
	{` http://foo.com/bar more`, `http://foo.com/bar`},
	{`<http://foo.com/bar>`, `http://foo.com/bar`},
	{`<http://foo.com/bar>more`, `http://foo.com/bar`},
	{`,http://foo.com/bar.`, `http://foo.com/bar`},
	{`,http://foo.com/bar.more`, `http://foo.com/bar.more`},
	{`,http://foo.com/bar,`, `http://foo.com/bar`},
	{`,http://foo.com/bar,more`, `http://foo.com/bar,more`},
	{`(http://foo.com/bar)`, `http://foo.com/bar`},
	{`(http://foo.com/bar)more`, `http://foo.com/bar)more`},
	{`"http://foo.com/bar'`, `http://foo.com/bar`},
	{`"http://foo.com/bar'more`, `http://foo.com/bar'more`},
	{`"http://foo.com/bar"`, `http://foo.com/bar`},
	{`"http://foo.com/bar"more`, `http://foo.com/bar"more`},
	{`http://a.b/a.,:;-+_()?@&=$~!*%'"a`, `http://a.b/a.,:;-+_()?@&=$~!*%'"a`},
	{`http://foo.com/path_(more)`, `http://foo.com/path_(more)`},
	{`http://test.foo.com/`, `http://test.foo.com/`},
	{`http://foo.com/path`, `http://foo.com/path`},
	{`http://foo.com:8080/path`, `http://foo.com:8080/path`},
	{`http://1.1.1.1/path`, `http://1.1.1.1/path`},
	{`http://1080::8:800:200c:417a/path`, `http://1080::8:800:200c:417a/path`},
	{`what is http://foo.com?`, `http://foo.com`},
	{`the http://foo.com!`, `http://foo.com`},
	{`https://test.foo.bar/path?a=b`, `https://test.foo.bar/path?a=b`},
	{`ftp://user@foo.bar`, `ftp://user@foo.bar`},
}

func doTest(t *testing.T, re *regexp.Regexp, cases []regexTestCase) {
	for _, c := range cases {
		got := re.FindString(c.in)
		var want string
		switch x := c.want.(type) {
		case string:
			want = x
		}
		if got != want {
			t.Errorf(`xurls.All.FindString("%s") got "%s", want "%s"`, c.in, got, want)
		}
	}
}

func TestAll(t *testing.T) {
	doTest(t, All, alwaysNegative)
	doTest(t, All, alwaysPositive)
	doTest(t, All, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, `foo.com`},
		{`foo.com bar.com`, `foo.com`},
		{`foo.com-foo`, `foo.com`},
		{`foo.onion`, `foo.onion`},
		{`foo.i2p`, `foo.i2p`},
		{`中国.中国`, `中国.中国`},
		{`中国.中国/foo中国`, `中国.中国/foo中国`},
		{`foo.com/`, `foo.com/`},
		{`1.1.1.1`, `1.1.1.1`},
		{`121.1.1.1`, `121.1.1.1`},
		{`255.1.1.1`, `255.1.1.1`},
		{`300.1.1.1`, nil},
		{`1080:0:0:0:8:800:200C:4171`, `1080:0:0:0:8:800:200C:4171`},
		{`3ffe:2a00:100:7031::1`, `3ffe:2a00:100:7031::1`},
		{`1080::8:800:200c:417a`, `1080::8:800:200c:417a`},
		{`foo.com:8080`, `foo.com:8080`},
		{`foo.com:8080/path`, `foo.com:8080/path`},
		{`test.foo.com`, `test.foo.com`},
		{`test.foo.com/path`, `test.foo.com/path`},
		{`test.foo.com/path/more/`, `test.foo.com/path/more/`},
		{`TEST.FOO.COM/PATH`, `TEST.FOO.COM/PATH`},
		{`foo.com/a.,:;-+_()?@&=$~!*%'"a`, `foo.com/a.,:;-+_()?@&=$~!*%'"a`},
		{`foo.com/path_(more)`, `foo.com/path_(more)`},
		{`foo.com/path_(even)_(more)`, `foo.com/path_(even)_(more)`},
		{`foo.com/path_(more)/more`, `foo.com/path_(more)/more`},
		{`foo.com/path_(more)/end)`, `foo.com/path_(more)/end)`},
		{`www.foo.com`, `www.foo.com`},
		{` foo.com/bar `, `foo.com/bar`},
		{` foo.com/bar more`, `foo.com/bar`},
		{`<foo.com/bar>`, `foo.com/bar`},
		{`<foo.com/bar>more`, `foo.com/bar`},
		{`,foo.com/bar.`, `foo.com/bar`},
		{`,foo.com/bar.more`, `foo.com/bar.more`},
		{`,foo.com/bar,`, `foo.com/bar`},
		{`,foo.com/bar,more`, `foo.com/bar,more`},
		{`(foo.com/bar)`, `foo.com/bar`},
		{`(foo.com/bar)more`, `foo.com/bar)more`},
		{`"foo.com/bar'`, `foo.com/bar`},
		{`"foo.com/bar'more`, `foo.com/bar'more`},
		{`"foo.com/bar"`, `foo.com/bar`},
		{`"foo.com/bar"more`, `foo.com/bar"more`},
		{`what is foo.com?`, `foo.com`},
		{`the foo.com!`, `foo.com`},

		{`foo@bar`, nil},
		{`foo@bar.a`, nil},
		{`foo@bar.com`, `foo@bar.com`},
		{`foo@bar.com bar@bar.com`, `foo@bar.com`},
		{`foo@bar.onion`, `foo@bar.onion`},
		{`foo@中国.中国`, `foo@中国.中国`},
		{`mailto:foo@bar.com`, `foo@bar.com`},
		{`foo@test.bar.com`, `foo@test.bar.com`},
		{`FOO@TEST.BAR.COM`, `FOO@TEST.BAR.COM`},
		{`foo@bar.com/path`, `foo@bar.com`},
		{`foo+test@bar.com`, `foo+test@bar.com`},
		{`foo+._%-@bar.com`, `foo+._%-@bar.com`},
	})
}

func TestAllStrict(t *testing.T) {
	doTest(t, AllStrict, alwaysNegative)
	doTest(t, AllStrict, alwaysPositive)
	doTest(t, AllStrict, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, nil},
		{`foo.com/`, nil},
		{`1.1.1.1`, nil},
		{`3ffe:2a00:100:7031::1`, nil},
		{`test.foo.com:8080/path`, nil},
		{`foo@bar.com`, nil},
	})
}
<|endoftext|>


<commit_before>package jsc

import (
	"log"
	"net/http"
	"net/url"
	"testing"

	"golang.org/x/net/context"

	"github.com/derekdowling/go-json-spec-handler"
	"github.com/derekdowling/jsh-api"
	. "github.com/smartystreets/goconvey/convey"
)

const testURL = "https://httpbin.org"

func TestClientRequest(t *testing.T) {

	Convey("Client Tests", t, func() {

		Convey("->setPath()", func() {
			url := &url.URL{Host: "test"}

			Convey("should format properly", func() {
				setPath(url, "tests")
				So(url.String(), ShouldEqual, "//test/tests")
			})

			Convey("should respect an existing path", func() {
				url.Path = "admin"
				setPath(url, "test")
				So(url.String(), ShouldEqual, "//test/admin/test")
			})
		})

		Convey("->setIDPath()", func() {
			url := &url.URL{Host: "test"}

			Convey("should format properly an id url", func() {
				setIDPath(url, "tests", "1")
				So(url.String(), ShouldEqual, "//test/tests/1")
			})
		})

	})
}

func TestParseResponse(t *testing.T) {

	Convey("ParseResponse", t, func() {

		response := &http.Response{
			StatusCode: http.StatusNotFound,
		}

		Convey("404 response parsing should not return a 406 error", func() {
			doc, err := ParseResponse(response)
			So(doc, ShouldBeNil)
			So(err, ShouldBeNil)
		})
	})
}

func TestResponseParsing(t *testing.T) {

	Convey("Response Parsing Tests", t, func() {

		Convey("Parse Object", func() {

			obj, objErr := jsh.NewObject("123", "test", map[string]string{"test": "test"})
			So(objErr, ShouldBeNil)

			response, err := mockObjectResponse(obj)
			So(err, ShouldBeNil)

			Convey("should parse successfully", func() {
				doc, err := Document(response)

				So(err, ShouldBeNil)
				So(doc.HasData(), ShouldBeTrue)
				So(doc.First().ID, ShouldEqual, "123")
			})
		})

		Convey("Parse List", func() {

			obj, objErr := jsh.NewObject("123", "test", map[string]string{"test": "test"})
			So(objErr, ShouldBeNil)

			list := jsh.List{obj, obj}

			response, err := mockListResponse(list)
			So(err, ShouldBeNil)

			Convey("should parse successfully", func() {
				doc, err := Document(response)

				So(err, ShouldBeNil)
				So(doc.HasData(), ShouldBeTrue)
				So(doc.First().ID, ShouldEqual, "123")
			})
		})
	})
}

// not a great for this, would much rather have it in test_util, but it causes an
// import cycle wit jsh-api
func testAPI() *jshapi.API {

	resource := jshapi.NewMockResource("tests", 1, nil)
	resource.Action("testAction", func(ctx context.Context, id string) (*jsh.Object, jsh.ErrorType) {
		object, err := jsh.NewObject("1", "tests", []string{"testAction"})
		if err != nil {
			log.Fatal(err.Error())
		}

		return object, nil
	})

	api := jshapi.New("", true)
	api.Add(resource)

	return api
}
<commit_msg>Fix failing unit test after SendHandler refactor<commit_after>package jsc

import (
	"log"
	"net/http"
	"net/url"
	"testing"

	"golang.org/x/net/context"

	"github.com/derekdowling/go-json-spec-handler"
	"github.com/derekdowling/jsh-api"
	. "github.com/smartystreets/goconvey/convey"
)

const testURL = "https://httpbin.org"

func TestClientRequest(t *testing.T) {

	Convey("Client Tests", t, func() {

		Convey("->setPath()", func() {
			url := &url.URL{Host: "test"}

			Convey("should format properly", func() {
				setPath(url, "tests")
				So(url.String(), ShouldEqual, "//test/tests")
			})

			Convey("should respect an existing path", func() {
				url.Path = "admin"
				setPath(url, "test")
				So(url.String(), ShouldEqual, "//test/admin/test")
			})
		})

		Convey("->setIDPath()", func() {
			url := &url.URL{Host: "test"}

			Convey("should format properly an id url", func() {
				setIDPath(url, "tests", "1")
				So(url.String(), ShouldEqual, "//test/tests/1")
			})
		})

	})
}

func TestParseResponse(t *testing.T) {

	Convey("ParseResponse", t, func() {

		response := &http.Response{
			StatusCode: http.StatusNotFound,
		}

		Convey("404 response parsing should not return a 406 error", func() {
			doc, err := ParseResponse(response)
			So(doc, ShouldBeNil)
			So(err, ShouldBeNil)
		})
	})
}

func TestResponseParsing(t *testing.T) {

	Convey("Response Parsing Tests", t, func() {

		Convey("Parse Object", func() {

			obj, objErr := jsh.NewObject("123", "test", map[string]string{"test": "test"})
			So(objErr, ShouldBeNil)

			response, err := mockObjectResponse(obj)
			So(err, ShouldBeNil)

			Convey("should parse successfully", func() {
				doc, err := Document(response)

				So(err, ShouldBeNil)
				So(doc.HasData(), ShouldBeTrue)
				So(doc.First().ID, ShouldEqual, "123")
			})
		})

		Convey("Parse List", func() {

			obj, objErr := jsh.NewObject("123", "test", map[string]string{"test": "test"})
			So(objErr, ShouldBeNil)

			list := jsh.List{obj, obj}

			response, err := mockListResponse(list)
			So(err, ShouldBeNil)

			Convey("should parse successfully", func() {
				doc, err := Document(response)

				So(err, ShouldBeNil)
				So(doc.HasData(), ShouldBeTrue)
				So(doc.First().ID, ShouldEqual, "123")
			})
		})
	})
}

// not a great for this, would much rather have it in test_util, but it causes an
// import cycle wit jsh-api
func testAPI() *jshapi.API {

	resource := jshapi.NewMockResource("tests", 1, nil)
	resource.Action("testAction", func(ctx context.Context, id string) (*jsh.Object, jsh.ErrorType) {
		object, err := jsh.NewObject("1", "tests", []string{"testAction"})
		if err != nil {
			log.Fatal(err.Error())
		}

		return object, nil
	})

	api := jshapi.New("")
	api.Add(resource)

	return api
}
<|endoftext|>


<commit_before>// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12,!gtk_3_14

// See: https://developer.gnome.org/gtk3/3.16/api-index-3-16.html

package gtk

// #include <gtk/gtk.h>
// #include "gtk_since_3_16.go.h"
import "C"
import (
	"sync"
	"unsafe"

	"github.com/gotk3/gotk3/gdk"
	"github.com/gotk3/gotk3/glib"
)

const (
	POLICY_EXTERNAL PolicyType = C.GTK_POLICY_EXTERNAL
)

func init() {
	tm := []glib.TypeMarshaler{

		// Objects/Interfaces
		{glib.Type(C.gtk_button_role_get_type()), marshalButtonRole},
		{glib.Type(C.gtk_popover_menu_get_type()), marshalPopoverMenu},
		{glib.Type(C.gtk_model_button_get_type()), marshalModelButton},
		{glib.Type(C.gtk_stack_sidebar_get_type()), marshalStackSidebar},
	}
	glib.RegisterGValueMarshalers(tm)

	//Contribute to casting
	for k, v := range map[string]WrapFn{
		"GtkPopoverMenu":  wrapPopoverMenu,
		"GtkModelButton":  wrapModelButton,
		"GtkStackSidebar": wrapStackSidebar,
	} {
		WrapMap[k] = v
	}
}

/*
 * Constants
 */

// ButtonRole is a representation of GTK's GtkButtonRole.
type ButtonRole int

const (
	BUTTON_ROLE_NORMAL ButtonRole = C.GTK_BUTTON_ROLE_NORMAL
	BUTTON_ROLE_CHECK  ButtonRole = C.GTK_BUTTON_ROLE_CHECK
	BUTTON_ROLE_RADIO  ButtonRole = C.GTK_BUTTON_ROLE_RADIO
)

func marshalButtonRole(p uintptr) (interface{}, error) {
	c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
	return ButtonRole(c), nil
}

/*
 * GtkStack
 */

// TODO:
// gtk_stack_set_hhomogeneous().
// gtk_stack_get_hhomogeneous().
// gtk_stack_set_vhomogeneous().
// gtk_stack_get_vhomogeneous().

/*
 * GtkNotebook
 */

// TODO:
// gtk_notebook_detach_tab().

/*
 * GtkListBox
 */

// ListBoxCreateWidgetFunc is a representation of GtkListBoxCreateWidgetFunc.
type ListBoxCreateWidgetFunc func(item interface{}, userData ...interface{}) int

type listBoxCreateWidgetFuncData struct {
	fn       ListBoxCreateWidgetFunc
	userData []interface{}
}

var (
	listBoxCreateWidgetFuncRegistry = struct {
		sync.RWMutex
		next int
		m    map[int]listBoxCreateWidgetFuncData
	}{
		next: 1,
		m:    make(map[int]listBoxCreateWidgetFuncData),
	}
)

/*
 * GtkScrolledWindow
 */

// SetOverlayScrolling is a wrapper around gtk_scrolled_window_set_overlay_scrolling().
func (v *ScrolledWindow) SetOverlayScrolling(scrolling bool) {
	C.gtk_scrolled_window_set_overlay_scrolling(v.native(), gbool(scrolling))
}

// GetOverlayScrolling is a wrapper around gtk_scrolled_window_get_overlay_scrolling().
func (v *ScrolledWindow) GetOverlayScrolling() bool {
	return gobool(C.gtk_scrolled_window_get_overlay_scrolling(v.native()))
}

/*
 * GtkPaned
 */

// SetWideHandle is a wrapper around gtk_paned_set_wide_handle().
func (v *Paned) SetWideHandle(wide bool) {
	C.gtk_paned_set_wide_handle(v.native(), gbool(wide))
}

// GetWideHandle is a wrapper around gtk_paned_get_wide_handle().
func (v *Paned) GetWideHandle() bool {
	return gobool(C.gtk_paned_get_wide_handle(v.native()))
}

/*
 * GtkLabel
 */

// GetXAlign is a wrapper around gtk_label_get_xalign().
func (v *Label) GetXAlign() float64 {
	c := C.gtk_label_get_xalign(v.native())
	return float64(c)
}

// GetYAlign is a wrapper around gtk_label_get_yalign().
func (v *Label) GetYAlign() float64 {
	c := C.gtk_label_get_yalign(v.native())
	return float64(c)
}

// SetXAlign is a wrapper around gtk_label_set_xalign().
func (v *Label) SetXAlign(n float64) {
	C.gtk_label_set_xalign(v.native(), C.gfloat(n))
}

// SetYAlign is a wrapper around gtk_label_set_yalign().
func (v *Label) SetYAlign(n float64) {
	C.gtk_label_set_yalign(v.native(), C.gfloat(n))
}

/*
* GtkModelButton
 */

// ModelButton is a representation of GTK's GtkModelButton.
type ModelButton struct {
	Button
}

func (v *ModelButton) native() *C.GtkModelButton {
	if v == nil || v.GObject == nil {
		return nil
	}

	p := unsafe.Pointer(v.GObject)
	return C.toGtkModelButton(p)
}

func marshalModelButton(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapModelButton(glib.Take(unsafe.Pointer(c))), nil
}

func wrapModelButton(obj *glib.Object) *ModelButton {
	actionable := wrapActionable(obj)
	return &ModelButton{Button{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, actionable}}
}

// ModelButtonNew is a wrapper around gtk_model_button_new
func ModelButtonNew() (*ModelButton, error) {
	c := C.gtk_model_button_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapModelButton(glib.Take(unsafe.Pointer(c))), nil
}

/*
 * GtkPopoverMenu
 */

// PopoverMenu is a representation of GTK's GtkPopoverMenu.
type PopoverMenu struct {
	Popover
}

func (v *PopoverMenu) native() *C.GtkPopoverMenu {
	if v == nil || v.GObject == nil {
		return nil
	}

	p := unsafe.Pointer(v.GObject)
	return C.toGtkPopoverMenu(p)
}

func marshalPopoverMenu(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapPopoverMenu(glib.Take(unsafe.Pointer(c))), nil
}

func wrapPopoverMenu(obj *glib.Object) *PopoverMenu {
	return &PopoverMenu{Popover{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}}
}

// PopoverMenuNew is a wrapper around gtk_popover_menu_new
func PopoverMenuNew() (*PopoverMenu, error) {
	c := C.gtk_popover_menu_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapPopoverMenu(glib.Take(unsafe.Pointer(c))), nil
}

// OpenSubmenu is a wrapper around gtk_popover_menu_open_submenu
func (v *PopoverMenu) OpenSubmenu(name string) {
	cstr1 := (*C.gchar)(C.CString(name))
	defer C.free(unsafe.Pointer(cstr1))

	C.gtk_popover_menu_open_submenu(v.native(), cstr1)
}

/*
 * GtkStackSidebar
 */

// StackSidebar is a representation of GTK's GtkStackSidebar.
type StackSidebar struct {
	Bin
}

// native returns a pointer to the underlying GtkStack.
func (v *StackSidebar) native() *C.GtkStackSidebar {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkStackSidebar(p)
}

func marshalStackSidebar(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapStackSidebar(obj), nil
}

func wrapStackSidebar(obj *glib.Object) *StackSidebar {
	return &StackSidebar{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}
}

// StackSidebarNew is a wrapper around gtk_stack_sidebar_new().
func StackSidebarNew() (*StackSidebar, error) {
	c := C.gtk_stack_sidebar_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapStackSidebar(glib.Take(unsafe.Pointer(c))), nil
}

// SetStack is a wrapper around gtk_stack_sidebar_set_stack().
func (v *StackSidebar) SetStack(stack *Stack) {
	C.gtk_stack_sidebar_set_stack(v.native(), stack.native())
}

// GetStack is a wrapper around gtk_stack_sidebar_get_stack().
func (v *StackSidebar) GetStack() *Stack {
	c := C.gtk_stack_sidebar_get_stack(v.native())
	if c == nil {
		return nil
	}
	return wrapStack(glib.Take(unsafe.Pointer(c)))
}

/*
 * GtkEntry
 */

// GrabFocusWithoutSelecting is a wrapper for gtk_entry_grab_focus_without_selecting()
func (v *Entry) GrabFocusWithoutSelecting() {
	C.gtk_entry_grab_focus_without_selecting(v.native())
}

/*
 * GtkSearchEntry
 */

// HandleEvent is a wrapper around gtk_search_entry_handle_event().
func (v *SearchEntry) HandleEvent(event *gdk.Event) {
	e := (*C.GdkEvent)(unsafe.Pointer(event.Native()))
	C.gtk_search_entry_handle_event(v.native(), e)
}

/*
 * GtkTextBuffer
 */

// InsertMarkup is a wrapper around  gtk_text_buffer_insert_markup()
func (v *TextBuffer) InsertMarkup(start *TextIter, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_text_buffer_insert_markup(v.native(), (*C.GtkTextIter)(start), (*C.gchar)(cstr), C.gint(len(text)))
}

/*
 * CssProvider
 */

// LoadFromResource is a wrapper around gtk_css_provider_load_from_resource().
//
// See: https://developer.gnome.org/gtk3/stable/GtkCssProvider.html#gtk-css-provider-load-from-resource
func (v *CssProvider) LoadFromResource(path string) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	C.gtk_css_provider_load_from_resource(v.native(), (*C.gchar)(cpath))
}
<commit_msg>Add TextView func 3.16<commit_after>// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12,!gtk_3_14

// See: https://developer.gnome.org/gtk3/3.16/api-index-3-16.html

package gtk

// #include <gtk/gtk.h>
// #include "gtk_since_3_16.go.h"
import "C"
import (
	"sync"
	"unsafe"

	"github.com/gotk3/gotk3/gdk"
	"github.com/gotk3/gotk3/glib"
)

const (
	POLICY_EXTERNAL PolicyType = C.GTK_POLICY_EXTERNAL
)

func init() {
	tm := []glib.TypeMarshaler{

		// Objects/Interfaces
		{glib.Type(C.gtk_button_role_get_type()), marshalButtonRole},
		{glib.Type(C.gtk_popover_menu_get_type()), marshalPopoverMenu},
		{glib.Type(C.gtk_model_button_get_type()), marshalModelButton},
		{glib.Type(C.gtk_stack_sidebar_get_type()), marshalStackSidebar},
	}
	glib.RegisterGValueMarshalers(tm)

	//Contribute to casting
	for k, v := range map[string]WrapFn{
		"GtkPopoverMenu":  wrapPopoverMenu,
		"GtkModelButton":  wrapModelButton,
		"GtkStackSidebar": wrapStackSidebar,
	} {
		WrapMap[k] = v
	}
}

/*
 * Constants
 */

// ButtonRole is a representation of GTK's GtkButtonRole.
type ButtonRole int

const (
	BUTTON_ROLE_NORMAL ButtonRole = C.GTK_BUTTON_ROLE_NORMAL
	BUTTON_ROLE_CHECK  ButtonRole = C.GTK_BUTTON_ROLE_CHECK
	BUTTON_ROLE_RADIO  ButtonRole = C.GTK_BUTTON_ROLE_RADIO
)

func marshalButtonRole(p uintptr) (interface{}, error) {
	c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
	return ButtonRole(c), nil
}

/*
 * GtkStack
 */

// TODO:
// gtk_stack_set_hhomogeneous().
// gtk_stack_get_hhomogeneous().
// gtk_stack_set_vhomogeneous().
// gtk_stack_get_vhomogeneous().

/*
 * GtkNotebook
 */

// TODO:
// gtk_notebook_detach_tab().

/*
 * GtkListBox
 */

// ListBoxCreateWidgetFunc is a representation of GtkListBoxCreateWidgetFunc.
type ListBoxCreateWidgetFunc func(item interface{}, userData ...interface{}) int

type listBoxCreateWidgetFuncData struct {
	fn       ListBoxCreateWidgetFunc
	userData []interface{}
}

var (
	listBoxCreateWidgetFuncRegistry = struct {
		sync.RWMutex
		next int
		m    map[int]listBoxCreateWidgetFuncData
	}{
		next: 1,
		m:    make(map[int]listBoxCreateWidgetFuncData),
	}
)

/*
 * GtkScrolledWindow
 */

// SetOverlayScrolling is a wrapper around gtk_scrolled_window_set_overlay_scrolling().
func (v *ScrolledWindow) SetOverlayScrolling(scrolling bool) {
	C.gtk_scrolled_window_set_overlay_scrolling(v.native(), gbool(scrolling))
}

// GetOverlayScrolling is a wrapper around gtk_scrolled_window_get_overlay_scrolling().
func (v *ScrolledWindow) GetOverlayScrolling() bool {
	return gobool(C.gtk_scrolled_window_get_overlay_scrolling(v.native()))
}

/*
 * GtkPaned
 */

// SetWideHandle is a wrapper around gtk_paned_set_wide_handle().
func (v *Paned) SetWideHandle(wide bool) {
	C.gtk_paned_set_wide_handle(v.native(), gbool(wide))
}

// GetWideHandle is a wrapper around gtk_paned_get_wide_handle().
func (v *Paned) GetWideHandle() bool {
	return gobool(C.gtk_paned_get_wide_handle(v.native()))
}

/*
 * GtkLabel
 */

// GetXAlign is a wrapper around gtk_label_get_xalign().
func (v *Label) GetXAlign() float64 {
	c := C.gtk_label_get_xalign(v.native())
	return float64(c)
}

// GetYAlign is a wrapper around gtk_label_get_yalign().
func (v *Label) GetYAlign() float64 {
	c := C.gtk_label_get_yalign(v.native())
	return float64(c)
}

// SetXAlign is a wrapper around gtk_label_set_xalign().
func (v *Label) SetXAlign(n float64) {
	C.gtk_label_set_xalign(v.native(), C.gfloat(n))
}

// SetYAlign is a wrapper around gtk_label_set_yalign().
func (v *Label) SetYAlign(n float64) {
	C.gtk_label_set_yalign(v.native(), C.gfloat(n))
}

/*
* GtkModelButton
 */

// ModelButton is a representation of GTK's GtkModelButton.
type ModelButton struct {
	Button
}

func (v *ModelButton) native() *C.GtkModelButton {
	if v == nil || v.GObject == nil {
		return nil
	}

	p := unsafe.Pointer(v.GObject)
	return C.toGtkModelButton(p)
}

func marshalModelButton(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapModelButton(glib.Take(unsafe.Pointer(c))), nil
}

func wrapModelButton(obj *glib.Object) *ModelButton {
	actionable := wrapActionable(obj)
	return &ModelButton{Button{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, actionable}}
}

// ModelButtonNew is a wrapper around gtk_model_button_new
func ModelButtonNew() (*ModelButton, error) {
	c := C.gtk_model_button_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapModelButton(glib.Take(unsafe.Pointer(c))), nil
}

/*
 * GtkPopoverMenu
 */

// PopoverMenu is a representation of GTK's GtkPopoverMenu.
type PopoverMenu struct {
	Popover
}

func (v *PopoverMenu) native() *C.GtkPopoverMenu {
	if v == nil || v.GObject == nil {
		return nil
	}

	p := unsafe.Pointer(v.GObject)
	return C.toGtkPopoverMenu(p)
}

func marshalPopoverMenu(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapPopoverMenu(glib.Take(unsafe.Pointer(c))), nil
}

func wrapPopoverMenu(obj *glib.Object) *PopoverMenu {
	return &PopoverMenu{Popover{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}}
}

// PopoverMenuNew is a wrapper around gtk_popover_menu_new
func PopoverMenuNew() (*PopoverMenu, error) {
	c := C.gtk_popover_menu_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapPopoverMenu(glib.Take(unsafe.Pointer(c))), nil
}

// OpenSubmenu is a wrapper around gtk_popover_menu_open_submenu
func (v *PopoverMenu) OpenSubmenu(name string) {
	cstr1 := (*C.gchar)(C.CString(name))
	defer C.free(unsafe.Pointer(cstr1))

	C.gtk_popover_menu_open_submenu(v.native(), cstr1)
}

/*
 * GtkStackSidebar
 */

// StackSidebar is a representation of GTK's GtkStackSidebar.
type StackSidebar struct {
	Bin
}

// native returns a pointer to the underlying GtkStack.
func (v *StackSidebar) native() *C.GtkStackSidebar {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkStackSidebar(p)
}

func marshalStackSidebar(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapStackSidebar(obj), nil
}

func wrapStackSidebar(obj *glib.Object) *StackSidebar {
	return &StackSidebar{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}
}

// StackSidebarNew is a wrapper around gtk_stack_sidebar_new().
func StackSidebarNew() (*StackSidebar, error) {
	c := C.gtk_stack_sidebar_new()
	if c == nil {
		return nil, nilPtrErr
	}
	return wrapStackSidebar(glib.Take(unsafe.Pointer(c))), nil
}

// SetStack is a wrapper around gtk_stack_sidebar_set_stack().
func (v *StackSidebar) SetStack(stack *Stack) {
	C.gtk_stack_sidebar_set_stack(v.native(), stack.native())
}

// GetStack is a wrapper around gtk_stack_sidebar_get_stack().
func (v *StackSidebar) GetStack() *Stack {
	c := C.gtk_stack_sidebar_get_stack(v.native())
	if c == nil {
		return nil
	}
	return wrapStack(glib.Take(unsafe.Pointer(c)))
}

/*
 * GtkEntry
 */

// GrabFocusWithoutSelecting is a wrapper for gtk_entry_grab_focus_without_selecting()
func (v *Entry) GrabFocusWithoutSelecting() {
	C.gtk_entry_grab_focus_without_selecting(v.native())
}

/*
 * GtkSearchEntry
 */

// HandleEvent is a wrapper around gtk_search_entry_handle_event().
func (v *SearchEntry) HandleEvent(event *gdk.Event) {
	e := (*C.GdkEvent)(unsafe.Pointer(event.Native()))
	C.gtk_search_entry_handle_event(v.native(), e)
}

/*
 * GtkTextBuffer
 */

// InsertMarkup is a wrapper around  gtk_text_buffer_insert_markup()
func (v *TextBuffer) InsertMarkup(start *TextIter, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_text_buffer_insert_markup(v.native(), (*C.GtkTextIter)(start), (*C.gchar)(cstr), C.gint(len(text)))
}

/*
 * CssProvider
 */

// LoadFromResource is a wrapper around gtk_css_provider_load_from_resource().
//
// See: https://developer.gnome.org/gtk3/stable/GtkCssProvider.html#gtk-css-provider-load-from-resource
func (v *CssProvider) LoadFromResource(path string) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	C.gtk_css_provider_load_from_resource(v.native(), (*C.gchar)(cpath))
}

/*
 * GtkTextView
 */

// SetMonospace is a wrapper around  gtk_text_view_set_monospace()
func (v *TextView) SetMonospace(monospace bool) {
	C.gtk_text_view_set_monospace(v.native(), gbool(monospace))
}

// GetMonospace is a wrapper around  gtk_text_view_get_monospace()
func (v *TextView) GetMonospace() bool {
	return gobool(C.gtk_text_view_get_monospace(v.native()))
}

<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"strings"
)

type CheckPipe func(lc <-chan *Lexeme, outc chan<- *CheckedLexeme)

type CheckFunc func(string) bool

type CheckedWord struct {
	word    string
	suggest string
}

type CheckedLexeme struct {
	ctok  *Lexeme
	rule  string
	words []CheckedWord
}

type CheckedLexemes []*CheckedLexeme

// Implement sort.Interface.
func (s CheckedLexemes) Len() int { return len(s) }
func (s CheckedLexemes) Less(i, j int) bool {
	return s[i].ctok.pos.Filename < s[j].ctok.pos.Filename ||
		(s[i].ctok.pos.Filename == s[j].ctok.pos.Filename &&
			s[i].ctok.pos.Line < s[j].ctok.pos.Line) ||
		(s[i].ctok.pos.Filename == s[j].ctok.pos.Filename &&
			s[i].ctok.pos.Line == s[j].ctok.pos.Line &&
			s[i].ctok.pos.Column < s[j].ctok.pos.Column)
}
func (s CheckedLexemes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func WithPassIgnores(ignoreFile string) (CheckFunc, error) {
	ignmap := make(map[string]struct{})
	if ignoreFile != "" {
		igns, rerr := ioutil.ReadFile(ignoreFile)
		if rerr != nil {
			return nil, rerr
		}
		for _, word := range strings.Fields(string(igns)) {
			ignmap[word] = struct{}{}
		}
	}
	return func(word string) bool {
		_, ok := ignmap[word]
		return ok
	}, nil
}

func WithPassNumbers() CheckFunc {
	return func(word string) bool {
		// contains a number?
		for i := 0; i < len(word); i++ {
			if word[i] >= '0' && word[i] <= '9' {
				return true
			}
		}
		return false
	}
}

func Check(srcs []string, cps []CheckPipe) ([]*CheckedLexeme, error) {
	var err error
	errc := make(chan error)
	badcommc := make(chan *CheckedLexeme)
	badcomms := []*CheckedLexeme{}
	go func() {
		for comm := range badcommc {
			badcomms = append(badcomms, comm)
		}
		errc <- nil
	}()

	// process all files under all checkers
	for _, p := range srcs {
		lc, lerr := LexemeChan(p)
		if lerr != nil {
			go func() {
				errc <- lerr
				errc <- nil
			}()
			continue
		}
		mux := LexemeMux(lc, len(cps))
		for i := range cps {
			go func(k int) {
				cps[k](mux[k], badcommc)
				errc <- nil
			}(i)
		}
	}

	// wait for completion of readers
	for i := 0; i < len(srcs)*len(cps); i++ {
		if curErr := <-errc; curErr != nil {
			err = curErr
		}
	}

	// wait to collect all bad comments
	close(badcommc)
	<-errc

	return badcomms, err
}

func CheckAll(paths []string) ([]*CheckedLexeme, error) {
	sp, err := newSpellCheck(paths, "")
	if err != nil {
		return nil, err
	}
	defer sp.Close()
	cps := []CheckPipe{CheckGoDocs, sp.Check()}
	cts, cerr := Check(paths, cps)
	if cerr != nil {
		return nil, cerr
	}
	return cts, nil
}
<commit_msg>fix SelfPass failure introduced by previous commit<commit_after>package main

import (
	"io/ioutil"
	"strings"
)

type CheckPipe func(lc <-chan *Lexeme, outc chan<- *CheckedLexeme)

type CheckFunc func(string) bool

type CheckedWord struct {
	word    string
	suggest string
}

type CheckedLexeme struct {
	ctok  *Lexeme
	rule  string
	words []CheckedWord
}

type CheckedLexemes []*CheckedLexeme

// sort.Interface implementation:

func (s CheckedLexemes) Len() int { return len(s) }
func (s CheckedLexemes) Less(i, j int) bool {
	return s[i].ctok.pos.Filename < s[j].ctok.pos.Filename ||
		(s[i].ctok.pos.Filename == s[j].ctok.pos.Filename &&
			s[i].ctok.pos.Line < s[j].ctok.pos.Line) ||
		(s[i].ctok.pos.Filename == s[j].ctok.pos.Filename &&
			s[i].ctok.pos.Line == s[j].ctok.pos.Line &&
			s[i].ctok.pos.Column < s[j].ctok.pos.Column)
}
func (s CheckedLexemes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func WithPassIgnores(ignoreFile string) (CheckFunc, error) {
	ignmap := make(map[string]struct{})
	if ignoreFile != "" {
		igns, rerr := ioutil.ReadFile(ignoreFile)
		if rerr != nil {
			return nil, rerr
		}
		for _, word := range strings.Fields(string(igns)) {
			ignmap[word] = struct{}{}
		}
	}
	return func(word string) bool {
		_, ok := ignmap[word]
		return ok
	}, nil
}

func WithPassNumbers() CheckFunc {
	return func(word string) bool {
		// contains a number?
		for i := 0; i < len(word); i++ {
			if word[i] >= '0' && word[i] <= '9' {
				return true
			}
		}
		return false
	}
}

func Check(srcs []string, cps []CheckPipe) ([]*CheckedLexeme, error) {
	var err error
	errc := make(chan error)
	badcommc := make(chan *CheckedLexeme)
	badcomms := []*CheckedLexeme{}
	go func() {
		for comm := range badcommc {
			badcomms = append(badcomms, comm)
		}
		errc <- nil
	}()

	// process all files under all checkers
	for _, p := range srcs {
		lc, lerr := LexemeChan(p)
		if lerr != nil {
			go func() {
				errc <- lerr
				errc <- nil
			}()
			continue
		}
		mux := LexemeMux(lc, len(cps))
		for i := range cps {
			go func(k int) {
				cps[k](mux[k], badcommc)
				errc <- nil
			}(i)
		}
	}

	// wait for completion of readers
	for i := 0; i < len(srcs)*len(cps); i++ {
		if curErr := <-errc; curErr != nil {
			err = curErr
		}
	}

	// wait to collect all bad comments
	close(badcommc)
	<-errc

	return badcomms, err
}

func CheckAll(paths []string) ([]*CheckedLexeme, error) {
	sp, err := newSpellCheck(paths, "")
	if err != nil {
		return nil, err
	}
	defer sp.Close()
	cps := []CheckPipe{CheckGoDocs, sp.Check()}
	cts, cerr := Check(paths, cps)
	if cerr != nil {
		return nil, cerr
	}
	return cts, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package etcd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
	"time"

	"github.com/gravitational/satellite/monitoring"
	"github.com/gravitational/trace"
	"github.com/prometheus/client_golang/prometheus"

	log "github.com/Sirupsen/logrus"
)

const (
	namespace             = "etcd"
	collectMetricsTimeout = 5 * time.Second
)

var (
	followersLatency = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_latency"),
		"Bucketed histogram of latency time (s) between ETCD leader and follower",
		//			Buckets:   prometheus.ExponentialBuckets(0.0005, 2, 13), // buckets from 0.0001 till 4.096 sec
		[]string{"followerName"}, nil,
	)

	followersRaftFail = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_raft_fail"),
		"Counter of Raft RPC failed requests between ETCD leader and follower",
		[]string{"followerName"}, nil,
	)

	followersRaftSuccess = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_raft_success"),
		"Counter of Raft RPC successful requests between ETCD leader and follower",
		[]string{"followerName"}, nil,
	)
)

// LeaderStats is used by the leader in an etcd cluster, and encapsulates
// statistics about communication with its followers
// reference documentation https://github.com/coreos/etcd/blob/master/etcdserver/stats/leader.go
type LeaderStats struct {
	// Leader is the ID of the leader in the etcd cluster.
	Leader    string                    `json:"leader"`
	Followers map[string]*FollowerStats `json:"followers"`
	Message   string                    `json:"message"`
}

// FollowerStats encapsulates various statistics about a follower in an etcd cluster
type FollowerStats struct {
	Latency   LatencyStats `json:"latency"`
	RaftStats RaftStats    `json:"counts"`
}

// LatencyStats encapsulates latency statistics.
type LatencyStats struct {
	Current float64 `json:"current"`
}

// RaftStats encapsulates raft statistics.
type RaftStats struct {
	Fail    uint64 `json:"fail"`
	Success uint64 `json:"success"`
}

// Exporter collects ETCD stats from the given server and exports them using
// the prometheus metrics package.
type Exporter struct {
	client *http.Client
	config monitoring.ETCDConfig
	mutex  sync.RWMutex

	followersLatency     *prometheus.GaugeVec
	followersRaftFail    *prometheus.GaugeVec
	followersRaftSuccess *prometheus.GaugeVec
}

// NewExporter returns an initialized ETCDExporter.
func NewExporter(config *monitoring.ETCDConfig) (*Exporter, error) {
	transport, err := config.NewHTTPTransport()
	if err != nil {
		return nil, trace.Wrap(err)
	}

	client := &http.Client{
		Transport: transport,
		Timeout:   collectMetricsTimeout,
	}

	return &Exporter{
		client: client,
		config: *config,
		followersLatency: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_latency",
			Help:      "Latency time (s) between ETCD leader and follower",
		}, []string{"followerName"}),
		followersRaftFail: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_raft_fail",
			Help:      "Counter of Raft RPC failed requests between ETCD leader and follower",
		}, []string{"followerName"}),
		followersRaftSuccess: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_raft_success",
			Help:      "Counter of Raft RPC successful requests between ETCD leader and follower",
		}, []string{"followerName"}),
	}, nil
}

// Describe implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.followersLatency.Describe(ch)
	e.followersRaftFail.Describe(ch)
	e.followersRaftSuccess.Describe(ch)
}

func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
	for _, endpoint := range e.config.Endpoints {

		var leaderStats LeaderStats
		url := fmt.Sprintf("%v/v2/stats/leader", endpoint)

		resp, err := e.client.Get(url)
		if err != nil {
			return trace.Wrap(err)
		}
		defer resp.Body.Close()

		payload, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return trace.Wrap(err)
		}

		err = json.Unmarshal(payload, &leaderStats)
		if err != nil {
			return trace.Wrap(err)
		}

		if leaderStats.Message != "" {
			// Endpoint is not a leader of ETCD cluster
			continue
		}

		for id, follower := range leaderStats.Followers {
			e.followersRaftSuccess.WithLabelValues(id).Set(float64(follower.RaftStats.Success))
			e.followersRaftFail.WithLabelValues(id).Set(float64(follower.RaftStats.Fail))
			e.followersLatency.WithLabelValues(id).Set(follower.Latency.Current)
		}

		e.followersLatency.Collect(ch)
		e.followersRaftFail.Collect(ch)
		e.followersRaftSuccess.Collect(ch)
		return nil
	}
	return trace.Errorf("ETCD cluster has no leader")
}

// Collect fetches the stats from configured ETCD endpoint and delivers them
// as Prometheus metrics. It implements prometheus.Collector.
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
	e.mutex.Lock() // To protect metrics from concurrent collects.
	defer e.mutex.Unlock()
	if err := e.collect(ch); err != nil {
		log.Errorf("Error collecting stats from ETCD: %v", err)
	}
	return
}
<commit_msg>Get members name<commit_after>/*
Copyright 2017 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package etcd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
	"time"

	"github.com/gravitational/satellite/monitoring"
	"github.com/gravitational/trace"
	"github.com/prometheus/client_golang/prometheus"

	log "github.com/Sirupsen/logrus"
)

const (
	namespace             = "etcd"
	collectMetricsTimeout = 5 * time.Second
)

var (
	followersLatency = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_latency"),
		"Bucketed histogram of latency time (s) between ETCD leader and follower",
		//			Buckets:   prometheus.ExponentialBuckets(0.0005, 2, 13), // buckets from 0.0001 till 4.096 sec
		[]string{"followerName"}, nil,
	)

	followersRaftFail = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_raft_fail"),
		"Counter of Raft RPC failed requests between ETCD leader and follower",
		[]string{"followerName"}, nil,
	)

	followersRaftSuccess = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "etcd_followers_raft_success"),
		"Counter of Raft RPC successful requests between ETCD leader and follower",
		[]string{"followerName"}, nil,
	)
)

// LeaderStats is used by the leader in an etcd cluster, and encapsulates
// statistics about communication with its followers
// reference documentation https://github.com/coreos/etcd/blob/master/etcdserver/stats/leader.go
type LeaderStats struct {
	// Leader is the ID of the leader in the etcd cluster.
	Leader    string                    `json:"leader"`
	Followers map[string]*FollowerStats `json:"followers"`
	Message   string                    `json:"message"`
}

// FollowerStats encapsulates various statistics about a follower in an etcd cluster
type FollowerStats struct {
	Latency   LatencyStats `json:"latency"`
	RaftStats RaftStats    `json:"counts"`
}

// LatencyStats encapsulates latency statistics.
type LatencyStats struct {
	Current float64 `json:"current"`
}

// RaftStats encapsulates raft statistics.
type RaftStats struct {
	Fail    uint64 `json:"fail"`
	Success uint64 `json:"success"`
}

// Exporter collects ETCD stats from the given server and exports them using
// the prometheus metrics package.
type Exporter struct {
	client *http.Client
	config monitoring.ETCDConfig
	mutex  sync.RWMutex

	followersLatency     *prometheus.GaugeVec
	followersRaftFail    *prometheus.GaugeVec
	followersRaftSuccess *prometheus.GaugeVec
}

// NewExporter returns an initialized ETCDExporter.
func NewExporter(config *monitoring.ETCDConfig) (*Exporter, error) {
	transport, err := config.NewHTTPTransport()
	if err != nil {
		return nil, trace.Wrap(err)
	}

	client := &http.Client{
		Transport: transport,
		Timeout:   collectMetricsTimeout,
	}

	return &Exporter{
		client: client,
		config: *config,
		followersLatency: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_latency",
			Help:      "Latency time (s) between ETCD leader and follower",
		}, []string{"followerName"}),
		followersRaftFail: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_raft_fail",
			Help:      "Counter of Raft RPC failed requests between ETCD leader and follower",
		}, []string{"followerName"}),
		followersRaftSuccess: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "followers_raft_success",
			Help:      "Counter of Raft RPC successful requests between ETCD leader and follower",
		}, []string{"followerName"}),
	}, nil
}

// Describe implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.followersLatency.Describe(ch)
	e.followersRaftFail.Describe(ch)
	e.followersRaftSuccess.Describe(ch)
}

func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
	for _, endpoint := range e.config.Endpoints {

		var leaderStats LeaderStats
		url := fmt.Sprintf("%v/v2/stats/leader", endpoint)

		resp, err := e.client.Get(url)
		if err != nil {
			return trace.Wrap(err)
		}
		defer resp.Body.Close()

		payload, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return trace.Wrap(err)
		}

		err = json.Unmarshal(payload, &leaderStats)
		if err != nil {
			return trace.Wrap(err)
		}

		if leaderStats.Message != "" {
			// Endpoint is not a leader of ETCD cluster
			continue
		}
	membersMap, err := e.getMembers()
	if err != nil {
		return trace.Wrap(err)
	}

		for id, follower := range leaderStats.Followers {
			e.followersRaftSuccess.WithLabelValues(id).Set(float64(follower.RaftStats.Success))
			e.followersRaftFail.WithLabelValues(id).Set(float64(follower.RaftStats.Fail))
			e.followersLatency.WithLabelValues(id).Set(follower.Latency.Current)
		}

		e.followersLatency.Collect(ch)
		e.followersRaftFail.Collect(ch)
		e.followersRaftSuccess.Collect(ch)
		return nil
	}
	return trace.Errorf("ETCD cluster has no leader")
}

// Collect fetches the stats from configured ETCD endpoint and delivers them
// as Prometheus metrics. It implements prometheus.Collector.
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
	e.mutex.Lock() // To protect metrics from concurrent collects.
	defer e.mutex.Unlock()
	if err := e.collect(ch); err != nil {
		log.Errorf("error collecting stats from ETCD: %v", err)
	}
}

// Member represents simplified ETCD member struct
type Member struct {
	// ID of etcd cluster member
	ID string `json:"id"`
	// Name of etcd cluster member
	Name string `json:"name,omitempty"`
}

type Members struct {
	// List of etcd cluster members
	Members []Member `json:"members"`
}

func (e *Exporter) getMembers() (map[string]string, error) {
	var members Members
	resp, err := e.client.Get(e.client.Endpoint("stats", "leader"), url.Values{})
	if err != nil {
		return nil, trace.Wrap(err)
	}

	err = json.Unmarshal(resp.Bytes(), &members)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	membersMap := make(map[string]string)
	for _, member := range members.Members {
		membersMap[member.ID] = member.Name
	}
	return membersMap, nil
}

	}
	return
}
<|endoftext|>