<commit_before>package gomruby_test

import (
	. "."
	"errors"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"math"
	"testing"
)

func TestGoMRuby(t *testing.T) { TestingT(t) }

type F struct {
	m *MRuby
	c *LoadContext
}

var _ = Suite(&F{})

func (f *F) SetUpTest(c *C) {
	f.m = New()
	f.c = f.m.NewLoadContext("test.rb")
}

func (f *F) TearDownTest(c *C) {
	f.c.Delete()
	f.m.Delete()
}

func (f *F) TestLoad(c *C) {
	must := func(res interface{}, err error) interface{} {
		c.Check(err, IsNil)
		return res
	}

	c.Check(must(f.c.Load(`nil`)), Equals, nil)
	c.Check(must(f.c.Load(`true`)), Equals, true)
	c.Check(must(f.c.Load(`false`)), Equals, false)
	c.Check(must(f.c.Load(`1 + 1`)), Equals, 2)
	c.Check(must(f.c.Load(`1 - 1`)), Equals, 0)
	c.Check(must(f.c.Load(`1 - 2`)), Equals, -1)
	c.Check(must(f.c.Load(`3.14 + 42`)), Equals, 45.14)

	// assumes typedef int32_t mrb_int
	c.Check(must(f.c.Load(fmt.Sprintf("%d", math.MaxInt16))), Equals, math.MaxInt16)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", math.MaxUint16))), Equals, math.MaxUint16)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", math.MaxInt32))), Equals, math.MaxInt32)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", math.MaxUint32))), Equals, float64(math.MaxUint32))
	// c.Check(must(f.c.Load(fmt.Sprintf("%d", math.MaxInt64))), Equals, float64(math.MaxInt64)) // FIXME
	// TODO add math.MaxUint64

	c.Check(must(f.c.Load(`domain = "express" + "42" + ".com"`)), Equals, "express42.com")
	c.Check(must(f.c.Load(`domain`)), Equals, "express42.com")
	c.Check(must(f.c.Load(`""`)), Equals, "")

	slice := []interface{}{1, 3.14, "foo"}
	hash := map[interface{}]interface{}{"foo": 1, 3.14: "bar"}
	mix := []interface{}{42, map[interface{}]interface{}{3.14: []interface{}{"bar"}, "foo": 1}}
	c.Check(must(f.c.Load(`[1, 3.14, "foo"]`)), DeepEquals, slice)
	c.Check(must(f.c.Load(`{3.14=>"bar", "foo"=>1}`)), DeepEquals, hash)
	c.Check(must(f.c.Load(`[42, {3.14=>["bar"], "foo"=>1}]`)), DeepEquals, mix)

	c.Check(must(f.c.Load("ARGV.inspect")), Equals, `[]`)
	c.Check(must(f.c.Load("ARGV.inspect", nil, true, false)), Equals, `[nil, true, false]`)
	c.Check(must(f.c.Load("ARGV.inspect", 1, 3.14, "foo")), Equals, `[1, 3.14, "foo"]`)
	c.Check(must(f.c.Load("ARGV.inspect", slice)), Equals, `[[1, 3.14, "foo"]]`)
	c.Check(must(f.c.Load("ARGV.inspect", hash)), Equals, `[{3.14=>"bar", "foo"=>1}]`)
	c.Check(must(f.c.Load("ARGV.inspect", mix)), Equals, `[[42, {3.14=>["bar"], "foo"=>1}]]`)

	res, err := f.c.Load(`foo`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New(`test.rb:1: undefined method 'foo' for main (NoMethodError)`))

	res, err = f.c.Load(`
begin
  foo
rescue => e
  e.inspect
  e.inspect
`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New("SyntaxError: syntax error"))
}

func (f *F) TestLoadMore(c *C) {
	res, err := f.c.Load("ARGV.map { |x| x * x }", 1, 2, 3)
	c.Check(err, IsNil)
	c.Check(res, DeepEquals, []interface{}{1, 4, 9})
}

func (f *F) TestDefineGoConst(c *C) {
	f.m.DefineGoConst("MY_CONST", 42)
	res, err := f.c.Load("Go::MY_CONST")
	c.Check(err, IsNil)
	c.Check(res, Equals, 42)
}

func (f *F) TestLoadContext(c *C) {
	res, err := f.c.Load(`$global = 1; local = 2`)
	c.Check(res, Equals, 2)
	c.Check(err, IsNil)

	// state is preserved
	res, err = f.c.Load(`$global`)
	c.Check(res, Equals, 1)
	c.Check(err, IsNil)
	res, err = f.c.Load(`local`)
	c.Check(res, Equals, 2)
	c.Check(err, IsNil)

	c2 := f.m.NewLoadContext("test2.rb")
	defer c2.Delete()

	// global variable is accessible from other context
	res, err = c2.Load(`$global`)
	c.Check(res, Equals, 1)
	c.Check(err, IsNil)

	// local is not
	res, err = c2.Load(`local`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New("test2.rb:1: undefined method 'local' for main (NoMethodError)"))
}

func (f *F) TestBugRb(c *C) {
	b, err := ioutil.ReadFile("test.rb")
	c.Assert(err, IsNil)
	res, err := f.c.Load(string(b))
	c.Logf("%#v", res)
	c.Check(err, IsNil)
}
<commit_msg>More tests for ints.<commit_after>package gomruby_test

import (
	. "."
	"errors"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"math"
	"testing"
)

func TestGoMRuby(t *testing.T) { TestingT(t) }

type F struct {
	m *MRuby
	c *LoadContext
}

var _ = Suite(&F{})

func (f *F) SetUpTest(c *C) {
	f.m = New()
	f.c = f.m.NewLoadContext("test.rb")
}

func (f *F) TearDownTest(c *C) {
	f.c.Delete()
	f.m.Delete()
}

func (f *F) TestLoad(c *C) {
	must := func(res interface{}, err error) interface{} {
		c.Check(err, IsNil)
		return res
	}

	c.Check(must(f.c.Load(`nil`)), Equals, nil)
	c.Check(must(f.c.Load(`true`)), Equals, true)
	c.Check(must(f.c.Load(`false`)), Equals, false)
	c.Check(must(f.c.Load(`1 + 1`)), Equals, 2)
	c.Check(must(f.c.Load(`1 - 1`)), Equals, 0)
	c.Check(must(f.c.Load(`1 - 2`)), Equals, -1)
	c.Check(must(f.c.Load(`3.14 + 42`)), Equals, 45.14)

	// assumes typedef int32_t mrb_int
	c.Check(must(f.c.Load(fmt.Sprintf("%d", int16(math.MaxInt16)))), Equals, math.MaxInt16)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", uint16(math.MaxUint16)))), Equals, math.MaxUint16)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", int32(math.MaxInt32)))), Equals, math.MaxInt32)
	c.Check(must(f.c.Load(fmt.Sprintf("%d", uint32(math.MaxUint32)))), Equals, float64(math.MaxUint32))
	// c.Check(must(f.c.Load(fmt.Sprintf("%d", int64(math.MaxInt64)))), Equals, float64(math.MaxInt64)) // FIXME
	c.Check(must(f.c.Load(fmt.Sprintf("%d", uint64(math.MaxUint64)))), Equals, float64(math.MaxUint64))

	c.Check(must(f.c.Load(`domain = "express" + "42" + ".com"`)), Equals, "express42.com")
	c.Check(must(f.c.Load(`domain`)), Equals, "express42.com")
	c.Check(must(f.c.Load(`""`)), Equals, "")

	slice := []interface{}{1, 3.14, "foo"}
	hash := map[interface{}]interface{}{"foo": 1, 3.14: "bar"}
	mix := []interface{}{42, map[interface{}]interface{}{3.14: []interface{}{"bar"}, "foo": 1}}
	c.Check(must(f.c.Load(`[1, 3.14, "foo"]`)), DeepEquals, slice)
	c.Check(must(f.c.Load(`{3.14=>"bar", "foo"=>1}`)), DeepEquals, hash)
	c.Check(must(f.c.Load(`[42, {3.14=>["bar"], "foo"=>1}]`)), DeepEquals, mix)

	c.Check(must(f.c.Load("ARGV.inspect")), Equals, `[]`)
	c.Check(must(f.c.Load("ARGV.inspect", nil, true, false)), Equals, `[nil, true, false]`)
	c.Check(must(f.c.Load("ARGV.inspect", 1, 3.14, "foo")), Equals, `[1, 3.14, "foo"]`)
	c.Check(must(f.c.Load("ARGV.inspect", slice)), Equals, `[[1, 3.14, "foo"]]`)
	c.Check(must(f.c.Load("ARGV.inspect", hash)), Equals, `[{3.14=>"bar", "foo"=>1}]`)
	c.Check(must(f.c.Load("ARGV.inspect", mix)), Equals, `[[42, {3.14=>["bar"], "foo"=>1}]]`)

	res, err := f.c.Load(`foo`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New(`test.rb:1: undefined method 'foo' for main (NoMethodError)`))

	res, err = f.c.Load(`
begin
  foo
rescue => e
  e.inspect
  e.inspect
`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New("SyntaxError: syntax error"))
}

func (f *F) TestLoadMore(c *C) {
	res, err := f.c.Load("ARGV.map { |x| x * x }", 1, 2, 3)
	c.Check(err, IsNil)
	c.Check(res, DeepEquals, []interface{}{1, 4, 9})
}

func (f *F) TestDefineGoConst(c *C) {
	f.m.DefineGoConst("MY_CONST", 42)
	res, err := f.c.Load("Go::MY_CONST")
	c.Check(err, IsNil)
	c.Check(res, Equals, 42)
}

func (f *F) TestLoadContext(c *C) {
	res, err := f.c.Load(`$global = 1; local = 2`)
	c.Check(res, Equals, 2)
	c.Check(err, IsNil)

	// state is preserved
	res, err = f.c.Load(`$global`)
	c.Check(res, Equals, 1)
	c.Check(err, IsNil)
	res, err = f.c.Load(`local`)
	c.Check(res, Equals, 2)
	c.Check(err, IsNil)

	c2 := f.m.NewLoadContext("test2.rb")
	defer c2.Delete()

	// global variable is accessible from other context
	res, err = c2.Load(`$global`)
	c.Check(res, Equals, 1)
	c.Check(err, IsNil)

	// local is not
	res, err = c2.Load(`local`)
	c.Check(res, Equals, nil)
	c.Check(err, DeepEquals, errors.New("test2.rb:1: undefined method 'local' for main (NoMethodError)"))
}

func (f *F) TestBugRb(c *C) {
	b, err := ioutil.ReadFile("test.rb")
	c.Assert(err, IsNil)
	res, err := f.c.Load(string(b))
	c.Logf("%#v", res)
	c.Check(err, IsNil)
}
<|endoftext|>


<commit_before>/*
gopm (Go Package Manager)
Copyright (c) 2012 cailei (dancercl@gmail.com)

The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
    "flag"
    "fmt"
    "github.com/cailei/gopm_index/gopm/index"
    "log"
    "os/exec"
    "strings"
)

func cmd_install(args []string) int {
    known, unknown := extract_unknown_flags(args)

    var help bool
    f := flag.NewFlagSet("install_flags", flag.ExitOnError)
    f.BoolVar(&help, "help", false, "show help info")
    f.BoolVar(&help, "h", false, "show help info")
    f.Usage = print_install_help
    f.Parse(known)

    if help {
        print_install_help()
        return 0
    }

    names := f.Args()
    if len(names) == 0 {
        fmt.Println("Please specify the packages you want to install.")
        return -1
    }

    db := openLocalDB()

    var exact_matches []*index.PackageMeta
    var partial_matches []*index.PackageMeta

    for pkg, err := db.FirstPackage(); pkg != nil; pkg, err = db.NextPackage() {
        if err != nil {
            log.Fatalln(err)
        }

        low_pkg_name := strings.ToLower(pkg.Name)

        for _, name := range names {
            low_name := strings.ToLower(name)
            if low_pkg_name == low_name {
                exact_matches = append(exact_matches, pkg)
            } else if strings.Contains(low_pkg_name, low_name) {
                partial_matches = append(partial_matches, pkg)
            }
        }
    }

    if len(partial_matches) > 0 {
        fmt.Println("Some packages cannot find a match, did you mean:")
        for _, p := range partial_matches {
            fmt.Printf("\t%v\n", p.Name)
        }
        return -1
    }

    if len(exact_matches) == 0 {
        fmt.Printf("Found nothing!\n")
    }

    var failed_pkgs []string
    for _, p := range exact_matches {
        succ := install_package(p, unknown)
        if !succ {
            failed_pkgs = append(failed_pkgs, p.Name)
        }
    }

    if len(failed_pkgs) > 0 {
        fmt.Println("These packages failed to install:")
        for _, name := range failed_pkgs {
            fmt.Printf("\t%v\n", name)
        }
        return -1
    }

    return 0
}

func install_package(pkg *index.PackageMeta, args []string) bool {
    fmt.Printf("Installing %v\n", pkg.Name)

    // try installing from repos
    succ := false
    for _, repo := range pkg.Repositories {
        succ = install_from_repo(repo, args)
        if succ {
            break
        }
    }

    if !succ {
        fmt.Println("Installation failed on all repos")
    }

    return succ
}

func install_from_repo(repo string, args []string) bool {
    var cmd_line []string
    cmd_line = append(cmd_line, []string{"go", "get"}...)
    cmd_line = append(cmd_line, args...)
    cmd_line = append(cmd_line, repo)
    //fmt.Printf("Running command: %v\n", cmd_line)
    cmd := exec.Command("go", cmd_line...)
    err := cmd.Run()
    if err != nil {
        fmt.Println(err)
        return false
    }
    return true
}

func extract_unknown_flags(args []string) (known []string, unknown []string) {
    for _, a := range args {
        if strings.HasPrefix(a, "-") {
            if a == "-h" || a == "--help" {
                known = append(known, a)
            } else {
                unknown = append(unknown, a)
            }
        } else {
            known = append(known, a)
        }
    }
    return
}

func print_install_help() {
    fmt.Print(`
gopm install <pkg1> [pkg2...]:
    install packages.

    this command will invoke 'go get' to get the job done, you may specify any valid 'go get' flags (see 'go get -h') in the command line, and they will be passed directly to the 'go get'.

e.g.
    'gopm install -u <package>'     install or upgrade a package
    'gopm install -a <package>'     install or upgrade a package

options:
    -h, -help       show help info

`)
}
<commit_msg>connect stdout/stderr/stdin of 'go get' to current process<commit_after>/*
gopm (Go Package Manager)
Copyright (c) 2012 cailei (dancercl@gmail.com)

The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
    "flag"
    "fmt"
    "github.com/cailei/gopm_index/gopm/index"
    "log"
    "os"
    "os/exec"
    "strings"
)

func cmd_install(args []string) int {
    known, unknown := extract_unknown_flags(args)

    var help bool
    f := flag.NewFlagSet("install_flags", flag.ExitOnError)
    f.BoolVar(&help, "help", false, "show help info")
    f.BoolVar(&help, "h", false, "show help info")
    f.Usage = print_install_help
    f.Parse(known)

    if help {
        print_install_help()
        return 0
    }

    names := f.Args()
    if len(names) == 0 {
        fmt.Println("Please specify the packages you want to install.")
        return -1
    }

    db := openLocalDB()

    var exact_matches []*index.PackageMeta
    var partial_matches []*index.PackageMeta

    for pkg, err := db.FirstPackage(); pkg != nil; pkg, err = db.NextPackage() {
        if err != nil {
            log.Fatalln(err)
        }

        low_pkg_name := strings.ToLower(pkg.Name)

        for _, name := range names {
            low_name := strings.ToLower(name)
            if low_pkg_name == low_name {
                exact_matches = append(exact_matches, pkg)
            } else if strings.Contains(low_pkg_name, low_name) {
                partial_matches = append(partial_matches, pkg)
            }
        }
    }

    if len(partial_matches) > 0 {
        fmt.Println("Some packages cannot find a match, did you mean:")
        for _, p := range partial_matches {
            fmt.Printf("\t%v\n", p.Name)
        }
        return -1
    }

    if len(exact_matches) == 0 {
        fmt.Printf("Found nothing!\n")
    }

    var failed_pkgs []string
    for _, p := range exact_matches {
        succ := install_package(p, unknown)
        if !succ {
            failed_pkgs = append(failed_pkgs, p.Name)
        }
    }

    if len(failed_pkgs) > 0 {
        fmt.Println("These packages failed to install:")
        for _, name := range failed_pkgs {
            fmt.Printf("\t%v\n", name)
        }
        return -1
    }

    return 0
}

func install_package(pkg *index.PackageMeta, args []string) bool {
    // try installing from repos
    succ := false
    for _, repo := range pkg.Repositories {
        fmt.Printf("Installing '%v' from (%v)\n", pkg.Name, repo)
        succ = install_from_repo(repo, args)
        if succ {
            break
        }
    }

    return succ
}

func install_from_repo(repo string, args []string) bool {
    var cmd_line []string
    cmd_line = append(cmd_line, "get")
    cmd_line = append(cmd_line, args...)
    cmd_line = append(cmd_line, repo)

    cmd := exec.Command("go", cmd_line...)
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err := cmd.Run()
    if err != nil {
        //fmt.Println(err)
        fmt.Println("Failed.\n")
        return false
    }

    fmt.Println("Done.\n")
    return true
}

func extract_unknown_flags(args []string) (known []string, unknown []string) {
    for _, a := range args {
        if strings.HasPrefix(a, "-") {
            if a == "-h" || a == "--help" {
                known = append(known, a)
            } else {
                unknown = append(unknown, a)
            }
        } else {
            known = append(known, a)
        }
    }
    return
}

func print_install_help() {
    fmt.Print(`
gopm install <pkg1> [pkg2...]:
    install packages.

    this command will invoke 'go get' to get the job done, you may specify any valid 'go get' flags (see 'go get -h') in the command line, and they will be passed directly to the 'go get'.

e.g.
    'gopm install -u <package>'     install or upgrade a package from network
    'gopm install -v <package>'     install a package and be verbose

options:
    -h, -help       show help info

`)
}
<|endoftext|>


<commit_before>package gopwned

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

var (
	NOTFOUND     = "Not found — the account could not be found and has therefore not been pwned"
	FOOBAR       = "[{Title:Adobe Name:Adobe Domain:adobe.com BreachDate:2013-10-4 AddedDate:2013-12-04T00:00:00Z PwnCount:152445165 Description:The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, encrypted password and a password hint in plain text. The password cryptography was poorly done and many were quickly resolved back to plain text. The unencrypted hints also disclosed much about the passwords adding further to the risk that hundreds of millions of Adobe customers already faced. DataClasses:[Email addresses Password hints Passwords Usernames] IsVerified:true LogoType:svg}]"
	BREACHES     = "[{Title:Adobe Name:Adobe Domain:adobe.com BreachDate:2013-10-4 AddedDate:2013-12-04T00:00:00Z PwnCount:152445165 Description:The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, encrypted password and a password hint in plain text. The password cryptography was poorly done and many were quickly resolved back to plain text. The unencrypted hints also disclosed much about the passwords adding further to the risk that hundreds of millions of Adobe customers already faced. DataClasses:[Email addresses Password hints Passwords Usernames] IsVerified:true LogoType:svg}]"
	SINGLEBREACH = "{Title:Adobe Name:Adobe Domain:adobe.com BreachDate:2013-10-4 AddedDate:2013-12-04T00:00:00Z PwnCount:152445165 Description:The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, encrypted password and a password hint in plain text. The password cryptography was poorly done and many were quickly resolved back to plain text. The unencrypted hints also disclosed much about the passwords adding further to the risk that hundreds of millions of Adobe customers already faced. DataClasses:[Email addresses Password hints Passwords Usernames] IsVerified:true LogoType:svg}"
	DATACLASSES  = "[Addresses Age groups Career levels Credit cards Customer interactions Dates of birth Education levels Email addresses Employers Genders Geographic location Government issued IDs Historical passwords Instant messenger identities IP addresses Job titles Languages MAC addresses Names Nicknames Passport numbers Password hints Passwords Phone numbers Private messages Purchases Reward program balances Salutations SMS messages Social connections Time zones User website URLs Usernames Website activity Years of birth]"
	PASTE        = "[{Source:Pastebin Id:9ZKSRx5i Title:1K Combo [CrackingSeal.net] Date:2015-04-19T13:06:08Z EmailCount:999} {Source:Pastebin Id:L6fZS5VC Title:kwekwekwekwk Date:2015-02-18T15:30:00Z EmailCount:14427} {Source:Pastebin Id:b6taeWri Title: Date:2014-11-17T08:11:00Z EmailCount:972} {Source:Pastebin Id:ba6LmF9Z Title:Hacked by Kashirmi Cheetah Date:2014-09-08T08:09:00Z EmailCount:1799} {Source:Pastebin Id:wXb5W8GV Title:#freenode-log Date:2014-07-06T19:07:00Z EmailCount:187} {Source:Pastebin Id:EE8GM0ed Title: Date:2014-03-26T17:03:00Z EmailCount:80} {Source:Pastebin Id:8Q0BvKD8 Title:syslog Date:2014-03-04T19:03:00Z EmailCount:139} {Source:Pastebin Id:C4GdBDnP Title:#secuinside13 logs Date:2013-05-26T22:05:00Z EmailCount:255}]"
)

func TestGoPwned(t *testing.T) {
	assert := assert.New(t)

	FBTest := GetAllBreachesForAccount("foo@bar.com", "adobe.com")
	assert.Equal(FBTest, FOOBAR, "they should be equal")

	NFResult := GetAllBreachesForAccount("mavjs01@gmail.com", "")
	assert.Equal(NFResult, NOTFOUND, "they should be equal")

	BRDomain := AllBreaches("adobe.com")
	assert.Equal(BREACHES, BRDomain, "they should be equal")

	BRALL := AllBreaches("")
	assert.NotEmpty(BRALL, "they should not be empty")
	assert.NotEqual(BREACHES, BRALL, "they should not be equal")

	GSBSite := GetSingleBreachedSite("adobe")
	assert.Equal(SINGLEBREACH, GSBSite, "they should be equal")

	CLS := GetAllDataClasses()
	assert.Equal(DATACLASSES, CLS, "they must be equal")

	PAccount := GetAllPastesForAccount("foo@bar.com")
	assert.Equal(PASTE, PAccount, "they should be equal")
}
<commit_msg>change test data<commit_after>package gopwned

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

var (
	NOTFOUND     = "Not found — the account could not be found and has therefore not been pwned"
	FOOBAR       = "[{\"Title\":\"Adobe\",\"Name\":\"Adobe\",\"Domain\":\"adobe.com\",\"BreachDate\":\"2013-10-4\",\"AddedDate\":\"2013-12-04T00:00:00Z\",\"PwnCount\":152445165,\"Description\":\"The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, \\u003cem\\u003eencrypted\\u003c/em\\u003e password and a password hint in plain text. The password cryptography was poorly done and \\u003ca href=\\\"http://stricture-group.com/files/adobe-top100.txt\\\" target=\\\"_blank\\\"\\u003emany were quickly resolved back to plain text\\u003c/a\\u003e. The unencrypted hints also \\u003ca href=\\\"http://www.troyhunt.com/2013/11/adobe-credentials-and-serious.html\\\" target=\\\"_blank\\\"\\u003edisclosed much about the passwords\\u003c/a\\u003e adding further to the risk that hundreds of millions of Adobe customers already faced.\",\"DataClasses\":[\"Email addresses\",\"Password hints\",\"Passwords\",\"Usernames\"],\"IsVerified\":true,\"LogoType\":\"svg\"}]"
	BREACHES     = "[{\"Title\":\"Adobe\",\"Name\":\"Adobe\",\"Domain\":\"adobe.com\",\"BreachDate\":\"2013-10-4\",\"AddedDate\":\"2013-12-04T00:00:00Z\",\"PwnCount\":152445165,\"Description\":\"The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, \\u003cem\\u003eencrypted\\u003c/em\\u003e password and a password hint in plain text. The password cryptography was poorly done and \\u003ca href=\\\"http://stricture-group.com/files/adobe-top100.txt\\\" target=\\\"_blank\\\"\\u003emany were quickly resolved back to plain text\\u003c/a\\u003e. The unencrypted hints also \\u003ca href=\\\"http://www.troyhunt.com/2013/11/adobe-credentials-and-serious.html\\\" target=\\\"_blank\\\"\\u003edisclosed much about the passwords\\u003c/a\\u003e adding further to the risk that hundreds of millions of Adobe customers already faced.\",\"DataClasses\":[\"Email addresses\",\"Password hints\",\"Passwords\",\"Usernames\"],\"IsVerified\":true,\"LogoType\":\"svg\"}]"
	SINGLEBREACH = "{\"Title\":\"Adobe\",\"Name\":\"Adobe\",\"Domain\":\"adobe.com\",\"BreachDate\":\"2013-10-4\",\"AddedDate\":\"2013-12-04T00:00:00Z\",\"PwnCount\":152445165,\"Description\":\"The big one. In October 2013, 153 million Adobe accounts were breached with each containing an internal ID, username, email, \\u003cem\\u003eencrypted\\u003c/em\\u003e password and a password hint in plain text. The password cryptography was poorly done and \\u003ca href=\\\"http://stricture-group.com/files/adobe-top100.txt\\\" target=\\\"_blank\\\"\\u003emany were quickly resolved back to plain text\\u003c/a\\u003e. The unencrypted hints also \\u003ca href=\\\"http://www.troyhunt.com/2013/11/adobe-credentials-and-serious.html\\\" target=\\\"_blank\\\"\\u003edisclosed much about the passwords\\u003c/a\\u003e adding further to the risk that hundreds of millions of Adobe customers already faced.\",\"DataClasses\":[\"Email addresses\",\"Password hints\",\"Passwords\",\"Usernames\"],\"IsVerified\":true,\"LogoType\":\"svg\"}"
	DATACLASSES  = "[\"Addresses\",\"Age groups\",\"Career levels\",\"Credit cards\",\"Customer interactions\",\"Dates of birth\",\"Education levels\",\"Email addresses\",\"Email bodies\",\"Employers\",\"Genders\",\"Geographic location\",\"Government issued IDs\",\"Historical passwords\",\"Instant messenger identities\",\"IP addresses\",\"Job titles\",\"Languages\",\"MAC addresses\",\"Names\",\"Nicknames\",\"Passport numbers\",\"Password hints\",\"Passwords\",\"Phone numbers\",\"Private messages\",\"Purchases\",\"Reward program balances\",\"Salutations\",\"SMS messages\",\"Social connections\",\"Time zones\",\"User website URLs\",\"Usernames\",\"Website activity\",\"Years of birth\"]"
	PASTE        = "[{\"Source\":\"Pastebin\",\"Id\":\"9ZKSRx5i\",\"Title\":\"1K Combo [CrackingSeal.net]\",\"Date\":\"2015-04-19T13:06:08Z\",\"EmailCount\":999},{\"Source\":\"Pastebin\",\"Id\":\"L6fZS5VC\",\"Title\":\"kwekwekwekwk\",\"Date\":\"2015-02-18T15:30:00Z\",\"EmailCount\":14427},{\"Source\":\"Pastebin\",\"Id\":\"b6taeWri\",\"Title\":\"\",\"Date\":\"2014-11-17T08:11:00Z\",\"EmailCount\":972},{\"Source\":\"Pastebin\",\"Id\":\"ba6LmF9Z\",\"Title\":\"Hacked by Kashirmi Cheetah\",\"Date\":\"2014-09-08T08:09:00Z\",\"EmailCount\":1799},{\"Source\":\"Pastebin\",\"Id\":\"wXb5W8GV\",\"Title\":\"#freenode-log\",\"Date\":\"2014-07-06T19:07:00Z\",\"EmailCount\":187},{\"Source\":\"Pastebin\",\"Id\":\"EE8GM0ed\",\"Title\":\"\",\"Date\":\"2014-03-26T17:03:00Z\",\"EmailCount\":80},{\"Source\":\"Pastebin\",\"Id\":\"8Q0BvKD8\",\"Title\":\"syslog\",\"Date\":\"2014-03-04T19:03:00Z\",\"EmailCount\":139},{\"Source\":\"Pastebin\",\"Id\":\"C4GdBDnP\",\"Title\":\"#secuinside13 logs\",\"Date\":\"2013-05-26T22:05:00Z\",\"EmailCount\":255}]"
)

func TestGoPwned(t *testing.T) {
	assert := assert.New(t)

	FBTest := GetAllBreachesForAccount("foo@bar.com", "adobe.com")
	assert.Equal(FBTest, FOOBAR, "they should be equal")

	NFResult := GetAllBreachesForAccount("mavjs01@gmail.com", "")
	assert.Equal(NFResult, NOTFOUND, "they should be equal")

	BRDomain := AllBreaches("adobe.com")
	assert.Equal(BREACHES, BRDomain, "they should be equal")

	BRALL := AllBreaches("")
	assert.NotEmpty(BRALL, "they should not be empty")
	assert.NotEqual(BREACHES, BRALL, "they should not be equal")

	GSBSite := GetSingleBreachedSite("adobe")
	assert.Equal(SINGLEBREACH, GSBSite, "they should be equal")

	CLS := GetAllDataClasses()
	assert.Equal(DATACLASSES, CLS, "they must be equal")

	PAccount := GetAllPastesForAccount("foo@bar.com")
	assert.Equal(PASTE, PAccount, "they should be equal")
}
<|endoftext|>


<commit_before>package randomword

import (
	"fmt"
	"math/rand"
	"strings"
)

const adjectives = `accountable
active
agile
anxious
appreciative
balanced
boisterous
bold
boring
brash
brave
bright
busy
chatty
cheerful
chipper
comedic
courteous
daring
delightful
empathic
excellent
exhausted
fantastic
fearless
fluent
forgiving
friendly
funny
generous
grateful
grouchy
grumpy
happy
hilarious
humble
impressive
insightful
intelligent
interested
kind
lean
nice
noisy
optimistic
patient
persistent
proud
quick
quiet
reflective
relaxed
reliable
responsible
responsive
rested
restless
shiny
shy
silly
sleepy
smart
spontaneous
surprised
sweet
talkative
terrific
thankful
timely
tired
turbulent
unexpected
wacky
wise
zany`

const nouns = `ardvark
aligator
antelope
baboon
badger
bandicoot
bat
bear
bilby
bongo
bonobo
buffalo
bushbuck
camel
cassowary
cat
cheetah
chimpanzee
chipmunk
civet
crane
crocodile
dingo
dog
dugong
duiker
echidna
eland
elephant
emu
fossa
fox
gazelle
gecko
gelada
genet
gerenuk
giraffe
gnu
gorilla
grysbok
hartebeest
hedgehog
hippopotamus
hyena
hyrax
impala
jackal
jaguar
kangaroo
klipspringer
koala
kob
kookaburra
kudu
lemur
leopard
lion
lizard
llama
lynx
manatee
mandrill
meerkat
mongoose
mouse
numbat
nyala
okapi
oribi
oryx
ostrich
otter
pangolin
panther
parrot
platypus
porcupine
possum
puku
quokka
quoll
rabbit
ratel
raven
reedbuck
rhinocerous
roan
sable
serval
shark
sitatunga
springhare
squirrel
sugar-glider
swan
tasmanian-devil
tiger
topi
turtle
wallaby
warthog
waterbuck
wildebeest
wolf
wolverine
wombat
zebra`

type Generator struct{}

func (gen Generator) Babble() string {
	return fmt.Sprintf("%s-%s", gen.RandomAdjective(), gen.RandomNoun())
}

func (Generator) RandomAdjective() string {
	return randomElement(adjectives)
}

func (Generator) RandomNoun() string {
	return randomElement(nouns)
}

func randomElement(fullList string) string {
	wordList := strings.Split(fullList, "\n")
	randomWordIndex := rand.Int() % len(wordList)

	return wordList[randomWordIndex]
}
<commit_msg>set the seed when generating random word<commit_after>package randomword

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

const adjectives = `accountable
active
agile
anxious
appreciative
balanced
boisterous
bold
boring
brash
brave
bright
busy
chatty
cheerful
chipper
comedic
courteous
daring
delightful
empathic
excellent
exhausted
fantastic
fearless
fluent
forgiving
friendly
funny
generous
grateful
grouchy
grumpy
happy
hilarious
humble
impressive
insightful
intelligent
interested
kind
lean
nice
noisy
optimistic
patient
persistent
proud
quick
quiet
reflective
relaxed
reliable
responsible
responsive
rested
restless
shiny
shy
silly
sleepy
smart
spontaneous
surprised
sweet
talkative
terrific
thankful
timely
tired
turbulent
unexpected
wacky
wise
zany`

const nouns = `ardvark
aligator
antelope
baboon
badger
bandicoot
bat
bear
bilby
bongo
bonobo
buffalo
bushbuck
camel
cassowary
cat
cheetah
chimpanzee
chipmunk
civet
crane
crocodile
dingo
dog
dugong
duiker
echidna
eland
elephant
emu
fossa
fox
gazelle
gecko
gelada
genet
gerenuk
giraffe
gnu
gorilla
grysbok
hartebeest
hedgehog
hippopotamus
hyena
hyrax
impala
jackal
jaguar
kangaroo
klipspringer
koala
kob
kookaburra
kudu
lemur
leopard
lion
lizard
llama
lynx
manatee
mandrill
meerkat
mongoose
mouse
numbat
nyala
okapi
oribi
oryx
ostrich
otter
pangolin
panther
parrot
platypus
porcupine
possum
puku
quokka
quoll
rabbit
ratel
raven
reedbuck
rhinocerous
roan
sable
serval
shark
sitatunga
springhare
squirrel
sugar-glider
swan
tasmanian-devil
tiger
topi
turtle
wallaby
warthog
waterbuck
wildebeest
wolf
wolverine
wombat
zebra`

type Generator struct{}

func (gen Generator) Babble() string {
	return fmt.Sprintf("%s-%s", gen.RandomAdjective(), gen.RandomNoun())
}

func (Generator) RandomAdjective() string {
	return randomElement(adjectives)
}

func (Generator) RandomNoun() string {
	return randomElement(nouns)
}

func randomElement(fullList string) string {
	rand.Seed(time.Now().UnixNano())
	wordList := strings.Split(fullList, "\n")
	randomWordIndex := rand.Int() % len(wordList)

	return wordList[randomWordIndex]
}
<|endoftext|>


<commit_before>package publish

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
	"sync/atomic"
	"time"

	MQTT "github.com/antlinker/mqtt-cli"

	"github.com/antlinker/alog"
	"gopkg.in/mgo.v2"

	"github.com/antlinker/go-cmap"
	"github.com/antlinker/mqttpersonal/config"
)

// Pub 执行Publish操作
func Pub(cfg *Config) {
	pub := &Publish{
		cfg:             cfg,
		lg:              alog.NewALog(),
		clientIndexData: make(map[string]int),
		clients:         cmap.NewConcurrencyMap(),
		execComplete:    make(chan bool, 1),
		end:             make(chan bool, 1),
		startTime:       time.Now(),
	}
	pub.lg.SetLogTag("PUBLISH")
	session, err := mgo.Dial(cfg.MongoUrl)
	if err != nil {
		pub.lg.Errorf("数据库连接发生异常:%s", err.Error())
		return
	}
	pub.session = session
	pub.database = session.DB(config.DataBase)
	err = pub.Init()
	if err != nil {
		pub.lg.Error(err)
		return
	}
	pub.ExecPublish()
	<-pub.end
	pub.lg.Info("执行完成.")
	time.Sleep(time.Second * 2)
	os.Exit(0)
}

type Publish struct {
	cfg             *Config
	lg              *alog.ALog
	session         *mgo.Session
	database        *mgo.Database
	clientData      []config.ClientInfo
	clientIndexData map[string]int
	clients         cmap.ConcurrencyMap
	publishID       int64
	execNum         int64
	execComplete    chan bool
	publishTotalNum int64
	publishNum      int64
	prePublishNum   int64
	maxPublishNum   int64
	arrPublishNum   []int64
	receiveTotalNum int64
	receiveNum      int64
	preReceiveNum   int64
	maxReceiveNum   int64
	arrReceiveNum   []int64
	end             chan bool
	startTime       time.Time
}

func (p *Publish) Init() error {
	err := p.initData()
	if err != nil {
		return err
	}
	err = p.initConnection()
	if err != nil {
		return err
	}
	p.lg.Info("初始化操作完成.")
	calcTicker := time.NewTicker(time.Second * 1)
	go p.calcMaxAndMinPacketNum(calcTicker)
	go p.checkComplete()
	prTicker := time.NewTicker(time.Duration(p.cfg.Interval) * time.Second)
	go p.pubAndRecOutput(prTicker)
	return nil
}

func (p *Publish) initData() error {
	p.lg.Info("开始客户端数据初始化...")
	err := p.database.C(config.C_Client).Find(nil).All(&p.clientData)
	if err != nil {
		return fmt.Errorf("初始化客户端数据发生异常:%s", err.Error())
	}
	for i := 0; i < len(p.clientData); i++ {
		client := p.clientData[i]
		p.clientIndexData[client.ClientID] = i
	}
	p.lg.Info("客户端数据初始化完成.")
	return nil
}

func (p *Publish) initConnection() error {
	p.lg.Info("开始建立MQTT数据连接初始化...")
	var wgroup sync.WaitGroup
	cl := len(p.clientData)
	wgroup.Add(cl)
	for i, l := 0, cl; i < l; i++ {
		go func(clientInfo config.ClientInfo) {
			defer wgroup.Done()
			clientID := clientInfo.ClientID
			opts := MQTT.NewClientOptions()
			opts.AddBroker(fmt.Sprintf("%s://%s", p.cfg.Network, p.cfg.Address))
			opts.SetClientID(clientID)
			opts.SetProtocolVersion(4)
			opts.SetAutoReconnect(p.cfg.AutoReconnect)
			opts.SetStore(MQTT.NewMemoryStore())
			if name, pwd := p.cfg.UserName, p.cfg.Password; name != "" && pwd != "" {
				opts.SetUsername(name)
				opts.SetPassword(pwd)
			}
			if v := p.cfg.KeepAlive; v > 0 {
				opts.SetKeepAlive(time.Duration(v) * time.Second)
			}
			if v := p.cfg.CleanSession; v {
				opts.SetCleanSession(v)
			}
			clientHandle := NewHandleConnect(clientID, p)
			opts.SetConnectionLostHandler(func(cli *MQTT.Client, err error) {
				clientHandle.ErrorHandle(err)
			})
			cli := MQTT.NewClient(opts)
			connectToken := cli.Connect()
			if connectToken.Wait() && connectToken.Error() != nil {
				p.lg.Errorf("客户端[%s]建立连接发生异常:%s", clientID, connectToken.Error().Error())
				return
			}
			topic := "C/" + clientID
			subToken := cli.Subscribe(topic, p.cfg.Qos, func(cli *MQTT.Client, msg MQTT.Message) {
				clientHandle.Subscribe([]byte(msg.Topic()), msg.Payload())
			})
			if subToken.Wait() && subToken.Error() != nil {
				p.lg.Errorf("客户端[%s]订阅主题发生异常:%s", clientID, subToken.Error().Error())
				return
			}
			p.clients.Set(clientID, cli)
		}(p.clientData[i])
	}
	wgroup.Wait()
	p.lg.Info("MQTT数据连接初始化完成.")
	return nil
}

func (p *Publish) checkComplete() {
	<-p.execComplete
	go func() {
		ticker := time.NewTicker(time.Millisecond * 500)
		for range ticker.C {
			if p.receiveNum == p.receiveTotalNum {
				ticker.Stop()
				p.end <- true
			}
		}
	}()
}

func (p *Publish) calcMaxAndMinPacketNum(ticker *time.Ticker) {
	for range ticker.C {
		pubNum := p.publishNum
		recNum := p.receiveNum
		pNum := pubNum - p.prePublishNum
		rNum := recNum - p.preReceiveNum
		if pNum > p.maxPublishNum {
			p.maxPublishNum = pNum
		}
		p.arrPublishNum = append(p.arrPublishNum, pNum)
		if rNum > p.maxReceiveNum {
			p.maxReceiveNum = rNum
		}
		p.arrReceiveNum = append(p.arrReceiveNum, rNum)
		p.prePublishNum = pubNum
		p.preReceiveNum = recNum
	}
}

func (p *Publish) pubAndRecOutput(ticker *time.Ticker) {
	for ct := range ticker.C {
		currentSecond := float64(ct.Sub(p.startTime)) / float64(time.Second)
		var psNum int64
		arrPNum := p.arrPublishNum
		if len(arrPNum) == 0 {
			continue
		}
		for i := 0; i < len(arrPNum); i++ {
			psNum += arrPNum[i]
		}
		avgPNum := psNum / int64(len(arrPNum))
		var rsNum int64
		arrRNum := p.arrReceiveNum
		for i := 0; i < len(arrRNum); i++ {
			rsNum += arrRNum[i]
		}
		avgRNum := rsNum / int64(len(arrRNum))
		clientNum := p.clients.Len()
		output := `
总耗时                      %.2fs
执行次数                    %d
客户端数量                  %d
应发包量                    %d
实际发包量                  %d
每秒平均的发包量            %d
每秒最大的发包量            %d
应收包量                    %d
实际收包量                  %d
每秒平均的接包量            %d
每秒最大的接包量            %d`

		fmt.Printf(output,
			currentSecond, p.execNum, clientNum, p.publishTotalNum, p.publishNum, avgPNum, p.maxPublishNum, p.receiveTotalNum, p.receiveNum, avgRNum, p.maxReceiveNum)
		fmt.Printf("\n")
	}
}

func (p *Publish) ExecPublish() {
	time.AfterFunc(time.Duration(p.cfg.Interval)*time.Second, func() {
		if p.execNum == int64(p.cfg.ExecNum) {
			p.lg.Info("发布已执行完成，等待接收订阅...")
			p.disconnect()
			p.execComplete <- true
			return
		}
		atomic.AddInt64(&p.execNum, 1)
		p.publish()
		p.ExecPublish()
	})
}

func (p *Publish) disconnect() {
	if v := p.cfg.DisconnectScale; v <= 0 || v > 100 || p.cfg.AutoReconnect {
		return
	}
	clientCount := p.clients.Len()
	disCount := int(float32(clientCount) * (float32(p.cfg.DisconnectScale) / 100))
	for _, v := range p.clients.ToMap() {
		cli := v.(*MQTT.Client)
		cli.Disconnect(100)
		disCount--
		if disCount == 0 {
			break
		}
	}
}

func (p *Publish) publish() {
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		pNum := len(clientInfo.Relations)
		p.publishTotalNum += int64(pNum)
		p.receiveTotalNum += int64(pNum)
		go p.userPublish(clientInfo)
	}
}

func (p *Publish) userPublish(clientInfo config.ClientInfo) {
	clientID := clientInfo.ClientID
	c, _ := p.clients.Get(clientID)
	cli := c.(*MQTT.Client)
	for j := 0; j < len(clientInfo.Relations); j++ {
		cTime := time.Now()
		sendPacket := config.PacketInfo{
			ID:        fmt.Sprintf("%d_%d", cTime.Unix(), atomic.AddInt64(&p.publishID, 1)),
			SendID:    clientID,
			ReceiveID: clientInfo.Relations[j],
			SendTime:  cTime,
		}
		if p.cfg.IsStore {
			err := p.database.C(config.C_Packet).Insert(sendPacket)
			if err != nil {
				p.lg.Errorf("Publish store error:%s", err.Error())
			}
		}
		bufData, err := json.Marshal(sendPacket)
		if err != nil {
			p.lg.Errorf("Publish json marshal error:%s", err.Error())
			continue
		}
		topic := "C/" + clientInfo.Relations[j]
		cli.Publish(topic, p.cfg.Qos, false, bufData)
		// if publishToken.Wait() && publishToken.Error() != nil {
		// 	p.lg.Errorf("客户端[%s]发布消息出现异常:%s", clientInfo.ClientID, publishToken.Error().Error())
		// 	continue
		// }
		atomic.AddInt64(&p.publishNum, 1)
		// 好友之间的发包间隔
		if v := p.cfg.UserInterval; v > 0 {
			time.Sleep(time.Duration(v) * time.Millisecond)
		}
	}
}
<commit_msg>Fixed publish questions<commit_after>package publish

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
	"sync/atomic"
	"time"

	MQTT "github.com/antlinker/mqtt-cli"

	"github.com/antlinker/alog"
	"gopkg.in/mgo.v2"

	"github.com/antlinker/go-cmap"
	"github.com/antlinker/mqttpersonal/config"
)

// Pub 执行Publish操作
func Pub(cfg *Config) {
	pub := &Publish{
		cfg:             cfg,
		lg:              alog.NewALog(),
		clientIndexData: make(map[string]int),
		clients:         cmap.NewConcurrencyMap(),
		execComplete:    make(chan bool, 1),
		end:             make(chan bool, 1),
		startTime:       time.Now(),
	}
	pub.lg.SetLogTag("PUBLISH")
	session, err := mgo.Dial(cfg.MongoUrl)
	if err != nil {
		pub.lg.Errorf("数据库连接发生异常:%s", err.Error())
		return
	}
	pub.session = session
	pub.database = session.DB(config.DataBase)
	err = pub.Init()
	if err != nil {
		pub.lg.Error(err)
		return
	}
	pub.ExecPublish()
	<-pub.end
	pub.lg.Info("执行完成.")
	time.Sleep(time.Second * 2)
	os.Exit(0)
}

type Publish struct {
	cfg             *Config
	lg              *alog.ALog
	session         *mgo.Session
	database        *mgo.Database
	clientData      []config.ClientInfo
	clientIndexData map[string]int
	clients         cmap.ConcurrencyMap
	publishID       int64
	execNum         int64
	execComplete    chan bool
	publishTotalNum int64
	publishNum      int64
	prePublishNum   int64
	maxPublishNum   int64
	arrPublishNum   []int64
	receiveTotalNum int64
	receiveNum      int64
	preReceiveNum   int64
	maxReceiveNum   int64
	arrReceiveNum   []int64
	end             chan bool
	startTime       time.Time
}

func (p *Publish) Init() error {
	err := p.initData()
	if err != nil {
		return err
	}
	err = p.initConnection()
	if err != nil {
		return err
	}
	p.lg.Info("初始化操作完成.")
	calcTicker := time.NewTicker(time.Second * 1)
	go p.calcMaxAndMinPacketNum(calcTicker)
	go p.checkComplete()
	prTicker := time.NewTicker(time.Duration(p.cfg.Interval) * time.Second)
	go p.pubAndRecOutput(prTicker)
	return nil
}

func (p *Publish) initData() error {
	p.lg.Info("开始客户端数据初始化...")
	err := p.database.C(config.C_Client).Find(nil).All(&p.clientData)
	if err != nil {
		return fmt.Errorf("初始化客户端数据发生异常:%s", err.Error())
	}
	for i := 0; i < len(p.clientData); i++ {
		client := p.clientData[i]
		p.clientIndexData[client.ClientID] = i
	}
	p.lg.Info("客户端数据初始化完成.")
	return nil
}

func (p *Publish) initConnection() error {
	p.lg.Info("开始建立MQTT数据连接初始化...")
	var wgroup sync.WaitGroup
	cl := len(p.clientData)
	wgroup.Add(cl)
	for i, l := 0, cl; i < l; i++ {
		go func(clientInfo config.ClientInfo) {
			defer wgroup.Done()
			clientID := clientInfo.ClientID
			opts := MQTT.NewClientOptions()
			opts.AddBroker(fmt.Sprintf("%s://%s", p.cfg.Network, p.cfg.Address))
			opts.SetClientID(clientID)
			opts.SetProtocolVersion(4)
			opts.SetAutoReconnect(p.cfg.AutoReconnect)
			opts.SetStore(MQTT.NewMemoryStore())
			if name, pwd := p.cfg.UserName, p.cfg.Password; name != "" && pwd != "" {
				opts.SetUsername(name)
				opts.SetPassword(pwd)
			}
			if v := p.cfg.KeepAlive; v > 0 {
				opts.SetKeepAlive(time.Duration(v) * time.Second)
			}
			if v := p.cfg.CleanSession; v {
				opts.SetCleanSession(v)
			}
			clientHandle := NewHandleConnect(clientID, p)
			opts.SetConnectionLostHandler(func(cli *MQTT.Client, err error) {
				clientHandle.ErrorHandle(err)
			})
		LB_RECONNECT:
			cli := MQTT.NewClient(opts)
			connectToken := cli.Connect()
			if connectToken.Wait() && connectToken.Error() != nil {
				// p.lg.Errorf("客户端[%s]建立连接发生异常:%s", clientID, connectToken.Error().Error())
				goto LB_RECONNECT
			}
			topic := "C/" + clientID
			subToken := cli.Subscribe(topic, p.cfg.Qos, func(cli *MQTT.Client, msg MQTT.Message) {
				clientHandle.Subscribe([]byte(msg.Topic()), msg.Payload())
			})
			if subToken.Wait() && subToken.Error() != nil {
				// p.lg.Errorf("客户端[%s]订阅主题发生异常:%s", clientID, subToken.Error().Error())
				// return
				goto LB_RECONNECT
			}
			p.clients.Set(clientID, cli)
		}(p.clientData[i])
	}
	wgroup.Wait()
	p.lg.Info("MQTT数据连接初始化完成.")
	return nil
}

func (p *Publish) checkComplete() {
	<-p.execComplete
	go func() {
		ticker := time.NewTicker(time.Millisecond * 500)
		for range ticker.C {
			if p.receiveNum == p.receiveTotalNum {
				ticker.Stop()
				p.end <- true
			}
		}
	}()
}

func (p *Publish) calcMaxAndMinPacketNum(ticker *time.Ticker) {
	for range ticker.C {
		pubNum := p.publishNum
		recNum := p.receiveNum
		pNum := pubNum - p.prePublishNum
		rNum := recNum - p.preReceiveNum
		if pNum > p.maxPublishNum {
			p.maxPublishNum = pNum
		}
		p.arrPublishNum = append(p.arrPublishNum, pNum)
		if rNum > p.maxReceiveNum {
			p.maxReceiveNum = rNum
		}
		p.arrReceiveNum = append(p.arrReceiveNum, rNum)
		p.prePublishNum = pubNum
		p.preReceiveNum = recNum
	}
}

func (p *Publish) pubAndRecOutput(ticker *time.Ticker) {
	for ct := range ticker.C {
		currentSecond := float64(ct.Sub(p.startTime)) / float64(time.Second)
		var psNum int64
		arrPNum := p.arrPublishNum
		if len(arrPNum) == 0 {
			continue
		}
		for i := 0; i < len(arrPNum); i++ {
			psNum += arrPNum[i]
		}
		avgPNum := psNum / int64(len(arrPNum))
		var rsNum int64
		arrRNum := p.arrReceiveNum
		for i := 0; i < len(arrRNum); i++ {
			rsNum += arrRNum[i]
		}
		avgRNum := rsNum / int64(len(arrRNum))
		clientNum := p.clients.Len()
		output := `
总耗时                      %.2fs
执行次数                    %d
客户端数量                  %d
应发包量                    %d
实际发包量                  %d
每秒平均的发包量            %d
每秒最大的发包量            %d
应收包量                    %d
实际收包量                  %d
每秒平均的接包量            %d
每秒最大的接包量            %d`

		fmt.Printf(output,
			currentSecond, p.execNum, clientNum, p.publishTotalNum, p.publishNum, avgPNum, p.maxPublishNum, p.receiveTotalNum, p.receiveNum, avgRNum, p.maxReceiveNum)
		fmt.Printf("\n")
	}
}

func (p *Publish) ExecPublish() {
	time.AfterFunc(time.Duration(p.cfg.Interval)*time.Second, func() {
		if p.execNum == int64(p.cfg.ExecNum) {
			p.lg.Info("发布已执行完成，等待接收订阅...")
			p.disconnect()
			p.execComplete <- true
			return
		}
		atomic.AddInt64(&p.execNum, 1)
		p.publish()
		p.ExecPublish()
	})
}

func (p *Publish) disconnect() {
	if v := p.cfg.DisconnectScale; v <= 0 || v > 100 || p.cfg.AutoReconnect {
		return
	}
	clientCount := p.clients.Len()
	disCount := int(float32(clientCount) * (float32(p.cfg.DisconnectScale) / 100))
	for _, v := range p.clients.ToMap() {
		cli := v.(*MQTT.Client)
		cli.Disconnect(100)
		disCount--
		if disCount == 0 {
			break
		}
	}
}

func (p *Publish) publish() {
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		pNum := len(clientInfo.Relations)
		p.publishTotalNum += int64(pNum)
		p.receiveTotalNum += int64(pNum)
		go p.userPublish(clientInfo)
	}
}

func (p *Publish) userPublish(clientInfo config.ClientInfo) {
	clientID := clientInfo.ClientID
	c, _ := p.clients.Get(clientID)
	if c == nil {
		return
	}
	cli := c.(*MQTT.Client)
	for j := 0; j < len(clientInfo.Relations); j++ {
		cTime := time.Now()
		sendPacket := config.PacketInfo{
			ID:        fmt.Sprintf("%d_%d", cTime.Unix(), atomic.AddInt64(&p.publishID, 1)),
			SendID:    clientID,
			ReceiveID: clientInfo.Relations[j],
			SendTime:  cTime,
		}
		if p.cfg.IsStore {
			err := p.database.C(config.C_Packet).Insert(sendPacket)
			if err != nil {
				p.lg.Errorf("Publish store error:%s", err.Error())
			}
		}
		bufData, err := json.Marshal(sendPacket)
		if err != nil {
			p.lg.Errorf("Publish json marshal error:%s", err.Error())
			continue
		}
		topic := "C/" + clientInfo.Relations[j]
		cli.Publish(topic, p.cfg.Qos, false, bufData)
		// if publishToken.Wait() && publishToken.Error() != nil {
		// 	p.lg.Errorf("客户端[%s]发布消息出现异常:%s", clientInfo.ClientID, publishToken.Error().Error())
		// 	continue
		// }
		atomic.AddInt64(&p.publishNum, 1)
		// 好友之间的发包间隔
		if v := p.cfg.UserInterval; v > 0 {
			time.Sleep(time.Duration(v) * time.Millisecond)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"

	log "github.com/gonet2/libs/nsq-logger"
)

import (
	"client_handler"
	"misc/packet"
	. "proto"
	"registry"
	. "types"
)

const (
	_port = ":51000"
)

const (
	SERVICE = "[GAME]"
)

var (
	ERROR_INCORRECT_FRAME_TYPE = errors.New("incorrect frame type")
	ERROR_SERVICE_NOT_BIND     = errors.New("service not bind")
	ERROR_USER_NOT_REGISTERED  = errors.New("user not registered")
)

type server struct{}

// stream receiver
func (s *server) recv(stream GameService_StreamServer, sess_die chan struct{}) chan *Game_Frame {
	ch := make(chan *Game_Frame, 1)
	go func() {
		defer func() {
			close(ch)
		}()
		for {
			in, err := stream.Recv()
			if err == io.EOF { // client closed
				return
			}

			if err != nil {
				log.Critical(err)
				return
			}
			select {
			case ch <- in:
			case <-sess_die:
			}
		}
	}()
	return ch
}

// stream server
func (s *server) Stream(stream GameService_StreamServer) error {
	defer utils.PrintPanicStack()
	// session init
	var sess Session
	sess_die := make(chan struct{})
	ch_agent := s.recv(stream, sess_die)
	ch_ipc := make(chan *Game_Frame, DEFAULT_CH_IPC_SIZE)

	defer func() {
		if sess.Flag&SESS_REGISTERED != 0 {
			// TODO: destroy session
			sess.Flag &^= SESS_REGISTERED
			registry.Unregister(sess.UserId)
		}
		close(sess_die)
		log.Trace("stream end:", sess.UserId)
	}()

	// >> main message loop <<
	for {
		select {
		case frame, ok := <-ch_agent: // frames from agent
			if !ok { // EOF
				return nil
			}
			switch frame.Type {
			case Game_Message:
				// validation
				if sess.Flag&SESS_REGISTERED == 0 {
					log.Critical("user not registered")
					return ERROR_USER_NOT_REGISTERED
				}

				// locate handler by proto number
				reader := packet.Reader(frame.Message)
				c, err := reader.ReadS16()
				if err != nil {
					log.Critical(err)
					return err
				}
				handle := client_handler.Handlers[c]
				if handle == nil {
					log.Criticalf("service not bind: %v", c)
					return ERROR_SERVICE_NOT_BIND

				}

				// handle request
				ret := handle(&sess, reader)

				// construct frame & return message from logic
				if ret != nil {
					if err := stream.Send(&Game_Frame{Type: Game_Message, Message: ret}); err != nil {
						log.Critical(err)
						return err
					}
				}

				// session control by logic
				if sess.Flag&SESS_KICKED_OUT != 0 { // logic kick out
					if err := stream.Send(&Game_Frame{Type: Game_Kick}); err != nil {
						log.Critical(err)
						return err
					}
					return nil
				}
			case Game_Register:
				if sess.Flag&SESS_REGISTERED == 0 {
					// TODO: create session
					sess.Flag |= SESS_REGISTERED
					sess.UserId = frame.UserId
					registry.Register(frame.UserId, ch_ipc)
					log.Trace("user registered")
				} else {
					log.Critical("user already registered")
				}
			case Game_Ping:
				if err := stream.Send(&Game_Frame{Type: Game_Ping, Message: frame.Message}); err != nil {
					log.Critical(err)
					return err
				}
				log.Trace("pinged")
			default:
				log.Criticalf("incorrect frame type: %v", frame.Type)
				return ERROR_INCORRECT_FRAME_TYPE
			}
		case frame := <-ch_ipc: // forward async messages from interprocess(goroutines) communication
			if err := stream.Send(frame); err != nil {
				log.Critical(err)
				return err
			}
		}
	}
}
<commit_msg>fix mistake<commit_after>package main

import (
	"errors"
	"io"

	log "github.com/gonet2/libs/nsq-logger"
)

import (
	"client_handler"
	"misc/packet"
	. "proto"
	"registry"
	. "types"
)

const (
	_port = ":51000"
)

const (
	SERVICE = "[GAME]"
)

var (
	ERROR_INCORRECT_FRAME_TYPE = errors.New("incorrect frame type")
	ERROR_SERVICE_NOT_BIND     = errors.New("service not bind")
	ERROR_USER_NOT_REGISTERED  = errors.New("user not registered")
)

type server struct{}

// stream receiver
func (s *server) recv(stream GameService_StreamServer, sess_die chan struct{}) chan *Game_Frame {
	ch := make(chan *Game_Frame, 1)
	go func() {
		defer func() {
			close(ch)
		}()
		for {
			in, err := stream.Recv()
			if err == io.EOF { // client closed
				return
			}

			if err != nil {
				log.Critical(err)
				return
			}
			select {
			case ch <- in:
			case <-sess_die:
			}
		}
	}()
	return ch
}

// stream server
func (s *server) Stream(stream GameService_StreamServer) error {
	defer PrintPanicStack()
	// session init
	var sess Session
	sess_die := make(chan struct{})
	ch_agent := s.recv(stream, sess_die)
	ch_ipc := make(chan *Game_Frame, DEFAULT_CH_IPC_SIZE)

	defer func() {
		if sess.Flag&SESS_REGISTERED != 0 {
			// TODO: destroy session
			sess.Flag &^= SESS_REGISTERED
			registry.Unregister(sess.UserId)
		}
		close(sess_die)
		log.Trace("stream end:", sess.UserId)
	}()

	// >> main message loop <<
	for {
		select {
		case frame, ok := <-ch_agent: // frames from agent
			if !ok { // EOF
				return nil
			}
			switch frame.Type {
			case Game_Message:
				// validation
				if sess.Flag&SESS_REGISTERED == 0 {
					log.Critical("user not registered")
					return ERROR_USER_NOT_REGISTERED
				}

				// locate handler by proto number
				reader := packet.Reader(frame.Message)
				c, err := reader.ReadS16()
				if err != nil {
					log.Critical(err)
					return err
				}
				handle := client_handler.Handlers[c]
				if handle == nil {
					log.Criticalf("service not bind: %v", c)
					return ERROR_SERVICE_NOT_BIND

				}

				// handle request
				ret := handle(&sess, reader)

				// construct frame & return message from logic
				if ret != nil {
					if err := stream.Send(&Game_Frame{Type: Game_Message, Message: ret}); err != nil {
						log.Critical(err)
						return err
					}
				}

				// session control by logic
				if sess.Flag&SESS_KICKED_OUT != 0 { // logic kick out
					if err := stream.Send(&Game_Frame{Type: Game_Kick}); err != nil {
						log.Critical(err)
						return err
					}
					return nil
				}
			case Game_Register:
				if sess.Flag&SESS_REGISTERED == 0 {
					// TODO: create session
					sess.Flag |= SESS_REGISTERED
					sess.UserId = frame.UserId
					registry.Register(frame.UserId, ch_ipc)
					log.Trace("user registered")
				} else {
					log.Critical("user already registered")
				}
			case Game_Ping:
				if err := stream.Send(&Game_Frame{Type: Game_Ping, Message: frame.Message}); err != nil {
					log.Critical(err)
					return err
				}
				log.Trace("pinged")
			default:
				log.Criticalf("incorrect frame type: %v", frame.Type)
				return ERROR_INCORRECT_FRAME_TYPE
			}
		case frame := <-ch_ipc: // forward async messages from interprocess(goroutines) communication
			if err := stream.Send(frame); err != nil {
				log.Critical(err)
				return err
			}
		}
	}
}
<|endoftext|>


<commit_before>package ls

import (
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"text/tabwriter"
)

var (
	flagSet       = flag.NewFlagSet("ls", flag.PanicOnError)
	longFlag      = flagSet.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flagSet.Bool("r", false, "Recurse into directories")
	humanFlag     = flagSet.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flagSet.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Ls(call []string) error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flagSet.PrintDefaults()
		return nil
	}

	dirs, e := getDirList()
	if e != nil {
		return e
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			return e
		}
	}
	out.Flush()
	return nil
}

func getDirList() ([]string, error) {
	if flagSet.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flagSet.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				return e
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	fmt.Fprintf(out, "%s%s\t", e.Name(), getEntryTypeString(e))
	if *longFlag {
		fmt.Fprintf(out, "%s\t", getModeString(e.Mode()))
		fmt.Fprintf(out, "%s\t", getSizeString(e.Size()))
		//fmt.Fprintf(out, "%s\t", getUserString(e.Uid))
	}
	fmt.Fprintln(out, "")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if mode&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%9dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("%7.3f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} else if e.Mode()&os.ModeDevice != 0 {
		return "<>"
	} else if e.Mode()&os.ModeNamedPipe != 0 {
		return ">>"
	} else if e.Mode()&os.ModeSymlink != 0 {
		return "@"
	} else if e.Mode()&os.ModeSocket != 0 {
		return "&"
	} else if e.Mode().IsRegular() && (e.Mode()&0001 == 0001) {
		return "*"
	}
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<commit_msg>Fix up ls output<commit_after>package ls

import (
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"text/tabwriter"
	"time"
)

var (
	flagSet       = flag.NewFlagSet("ls", flag.PanicOnError)
	longFlag      = flagSet.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flagSet.Bool("r", false, "Recurse into directories")
	humanFlag     = flagSet.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flagSet.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Ls(call []string) error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flagSet.PrintDefaults()
		return nil
	}

	dirs, e := getDirList()
	if e != nil {
		return e
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			return e
		}
	}
	out.Flush()
	return nil
}

func getDirList() ([]string, error) {
	if flagSet.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flagSet.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				return e
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	if *longFlag {
		if e.IsDir() {
			fmt.Print("d")
		} else {
			fmt.Print("-")
		}
		fmt.Fprintf(out, "%s ", getModeString(e.Mode()))
		fmt.Fprintf(out, "%s ", getSizeString(e.Size()))
		fmt.Fprintf(out, "%16s ", getTimeString(e.ModTime()))
	}
	fmt.Fprintf(out, "%s%s", e.Name(), getEntryTypeString(e))
	fmt.Fprintln(out, "")
}

func getTimeString(mtime time.Time) (s string) {
	return mtime.Format("2006-01-02 15:04")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if mode&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%6dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("% 6.1f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} else if e.Mode()&os.ModeDevice != 0 {
		return "<>"
	} else if e.Mode()&os.ModeNamedPipe != 0 {
		return ">>"
	} else if e.Mode()&os.ModeSymlink != 0 {
		return "@"
	} else if e.Mode()&os.ModeSocket != 0 {
		return "&"
	} else if e.Mode().IsRegular() && (e.Mode()&0001 == 0001) {
		return "*"
	}
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages. Use
// Config.Check to invoke the type checker for a package.
// Alternatively, create a new type checked with NewChecker
// and invoke it incrementally by calling Checker.Files.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (constant.Value)
// for every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
// For a tutorial, see https://golang.org/s/types-tutorial.
//
package types // import "go/types"

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/constant"
	"go/token"
)

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An Importer resolves import paths to Packages.
//
// CAUTION: This interface does not support the import of locally
// vendored packages. See https://golang.org/s/go15vendor.
// If possible, external implementations should implement ImporterFrom.
type Importer interface {
	// Import returns the imported package for the given import
	// path, or an error if the package couldn't be imported.
	// Two calls to Import with the same path return the same
	// package.
	Import(path string) (*Package, error)
}

// ImportMode is reserved for future use.
type ImportMode int

// An ImporterFrom resolves import paths to packages; it
// supports vendoring per https://golang.org/s/go15vendor.
// Use go/importer to obtain an ImporterFrom implementation.
type ImporterFrom interface {
	// Importer is present for backward-compatibility. Calling
	// Import(path) is the same as calling ImportFrom(path, "", 0);
	// i.e., locally vendored packages may not be found.
	// The types package does not call Import if an ImporterFrom
	// is present.
	Importer

	// ImportFrom returns the imported package for the given import
	// path when imported by the package in srcDir, or an error
	// if the package couldn't be imported. The mode value must
	// be 0; it is reserved for future use.
	// Two calls to ImportFrom with the same path and srcDir return
	// the same package.
	ImportFrom(path, srcDir string, mode ImportMode) (*Package, error)
}

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// An importer is used to import packages referred to from
	// import declarations.
	// If the installed importer implements ImporterFrom, the type
	// checker calls ImportFrom instead of Import.
	// The type checker reports an error if an importer is needed
	// but none was installed.
	Importer Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes

	// If DisableUnusedImportCheck is set, packages are not checked
	// for unused imports.
	DisableUnusedImportCheck bool
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, also their values. Invalid expressions are
	// omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// The Types map does not record the type of every identifier,
	// only those that appear where an arbitrary expression is
	// permitted. For instance, the identifier f in a selector
	// expression x.f is found only in the Selections map, the
	// identifier z in a variable declaration 'var z int' is found
	// only in the Defs map, and identifiers denoting packages in
	// qualified identifiers are collected in the Uses map.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, _ := e.(*ast.Ident); id != nil {
		if obj := info.ObjectOf(id); obj != nil {
			return obj.Type()
		}
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj, _ := info.Defs[id]; obj != nil {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value constant.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant_, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (https://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the lhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object and
// the first error if any. Additionally, if info != nil, Check populates each
// of the non-nil maps in the Info struct.
//
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T, nil) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<commit_msg>go/types: fix typo<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages. Use
// Config.Check to invoke the type checker for a package.
// Alternatively, create a new type checker with NewChecker
// and invoke it incrementally by calling Checker.Files.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (constant.Value)
// for every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
// For a tutorial, see https://golang.org/s/types-tutorial.
//
package types // import "go/types"

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/constant"
	"go/token"
)

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An Importer resolves import paths to Packages.
//
// CAUTION: This interface does not support the import of locally
// vendored packages. See https://golang.org/s/go15vendor.
// If possible, external implementations should implement ImporterFrom.
type Importer interface {
	// Import returns the imported package for the given import
	// path, or an error if the package couldn't be imported.
	// Two calls to Import with the same path return the same
	// package.
	Import(path string) (*Package, error)
}

// ImportMode is reserved for future use.
type ImportMode int

// An ImporterFrom resolves import paths to packages; it
// supports vendoring per https://golang.org/s/go15vendor.
// Use go/importer to obtain an ImporterFrom implementation.
type ImporterFrom interface {
	// Importer is present for backward-compatibility. Calling
	// Import(path) is the same as calling ImportFrom(path, "", 0);
	// i.e., locally vendored packages may not be found.
	// The types package does not call Import if an ImporterFrom
	// is present.
	Importer

	// ImportFrom returns the imported package for the given import
	// path when imported by the package in srcDir, or an error
	// if the package couldn't be imported. The mode value must
	// be 0; it is reserved for future use.
	// Two calls to ImportFrom with the same path and srcDir return
	// the same package.
	ImportFrom(path, srcDir string, mode ImportMode) (*Package, error)
}

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// An importer is used to import packages referred to from
	// import declarations.
	// If the installed importer implements ImporterFrom, the type
	// checker calls ImportFrom instead of Import.
	// The type checker reports an error if an importer is needed
	// but none was installed.
	Importer Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes

	// If DisableUnusedImportCheck is set, packages are not checked
	// for unused imports.
	DisableUnusedImportCheck bool
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, also their values. Invalid expressions are
	// omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// The Types map does not record the type of every identifier,
	// only those that appear where an arbitrary expression is
	// permitted. For instance, the identifier f in a selector
	// expression x.f is found only in the Selections map, the
	// identifier z in a variable declaration 'var z int' is found
	// only in the Defs map, and identifiers denoting packages in
	// qualified identifiers are collected in the Uses map.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, _ := e.(*ast.Ident); id != nil {
		if obj := info.ObjectOf(id); obj != nil {
			return obj.Type()
		}
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj, _ := info.Defs[id]; obj != nil {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value constant.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant_, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (https://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the lhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object and
// the first error if any. Additionally, if info != nil, Check populates each
// of the non-nil maps in the Info struct.
//
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T, nil) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<|endoftext|>