完成循环链表的单元测试

This commit is contained in:
huangsimin 2018-11-26 18:27:28 +08:00
parent c0a81a3c5f
commit 34c1468578
6 changed files with 364 additions and 25 deletions

View File

@ -1,22 +1,62 @@
package imitate
import (
"errors"
"io/ioutil"
"log"
"os"
"reflect"
"strings"
"github.com/davecgh/go-spew/spew"
yaml "gopkg.in/yaml.v2"
)
// YamlCurls 为了自定义序列化函数
type YamlCurls []string
// UnmarshalYAML YamlCurls反序列化函数
func (curls *YamlCurls) UnmarshalYAML(unmarshal func(interface{}) error) error {
var buf interface{}
err := unmarshal(&buf)
if err != nil {
return nil
}
switch tbuf := buf.(type) {
case string:
*curls = append(*curls, parseCurl(tbuf))
case []interface{}:
for _, ifa := range tbuf {
*curls = append(*curls, parseCurl(ifa.(string)))
}
default:
return errors.New("read curls is error, " + reflect.TypeOf(buf).String())
}
return nil
}
// MarshalYAML 序列化函数
func (curls *YamlCurls) MarshalYAML() (interface{}, error) {
content := "["
for _, curl := range []string(*curls) {
content += "\"" + curl + "\"" + ", "
}
content = strings.TrimRight(content, ", ")
content += "]"
return content, nil
}
// Config 任务加载的默认配置
type Config struct {
Session int `yaml:"session"`
Mode int `yaml:"mode"`
Proxies []string `yaml:"proxies"`
Retry int `yaml:"retry"`
Priority int `yaml:"priority"`
Curl string `yaml:"curl"`
Session int `yaml:"session"`
Mode int `yaml:"mode"`
Proxies []string `yaml:"proxies"`
Retry int `yaml:"retry"`
Priority int `yaml:"priority"`
Curls YamlCurls `yaml:"curls"`
ExecuteInterval `yaml:"execute_interval"`
ExecuteAt `yaml:"execute_at"`
@ -76,21 +116,21 @@ func NewConfig(p string) *Config {
if err != nil {
panic(err)
}
// spew.Dump(conf)
if conf.Curl == "" {
log.Println("the path ", p, "curl is \"\"")
} else {
if conf.Curl[0] == '@' {
curlfile, err := os.Open(conf.Curl[1:])
defer curlfile.Close()
if err != nil {
panic(err)
}
curldata, err := ioutil.ReadAll(curlfile)
conf.Curl = strings.Trim(string(curldata), "\r\n ")
}
}
spew.Dump(conf)
return conf
}
func parseCurl(curl string) string {
if curl[0] == '@' {
curlfile, err := os.Open(curl[1:])
defer curlfile.Close()
if err != nil {
panic(err)
}
curldata, err := ioutil.ReadAll(curlfile)
return strings.Trim(string(curldata), "\r\n ")
}
return strings.Trim(curl, "\r\n ")
}

View File

@ -34,6 +34,13 @@ type PlanResult struct {
Resp *requests.Response
}
// NewExecutePlan create a plan
func NewExecutePlan() *ExecutePlan {
plan := &ExecutePlan{}
return plan
}
// AppendIExecute 添加执行计划任务
func (ep *ExecutePlan) AppendIExecute(e IExecute) {
ep.ExecuteQueue = append(ep.ExecuteQueue, e)

View File

@ -15,13 +15,23 @@ type Person struct {
}
type Task struct {
GURL *curl2info.CURL
Curl *curl2info.CURL
Conf *Config
Plan *ExecutePlan
}
func NewTask(conf string, curlinfo string) *Task {
task := &Task{}
task.Conf = NewConfig(conf)
task.Curl = curl2info.NewCURL(curlinfo)
return task
}
func TestNewYaml(t *testing.T) {
data := spew.Sdump(NewConfig("test.yaml"))
if !(regexp.MustCompile(`Device: \(string\) \(len=12\) "eson-OnePlus"`).MatchString(data) && regexp.MustCompile(`Sec: \(int\) 30`).MatchString(data)) {
if !(regexp.MustCompile(`Device: \(string\) \(len=12\) "eson-OnePlus"`).MatchString(data) && regexp.MustCompile(`Sec: \(int\) 30`).MatchString(data) && regexp.MustCompile(`http://is.snssdk.com/2/article/information/v24/\?`).MatchString(data)) {
t.Error(data)
}
}
@ -41,3 +51,7 @@ func TestExecute(t *testing.T) {
log.Println(resp.Content())
}
}
func TestExecutePlan(t *testing.T) {
}

210
structure.go Normal file
View File

@ -0,0 +1,210 @@
package imitate
import (
"log"
"strings"
"github.com/davecgh/go-spew/spew"
)
// Node 循环链表 三色标记 不确定是否会清除循环引用, 网上说会
type Node struct {
value interface{}
prev *Node
next *Node
}
// CircularLinked 循环链表
type CircularLinked struct {
cursor *Node
head *Node
tail *Node
size uint64
}
// NewCircularLinked create a CircularLinked
func NewCircularLinked(values ...interface{}) *CircularLinked {
list := &CircularLinked{}
if len(values) > 0 {
list.Append(values...)
}
return list
}
// Cursor get current Cursor
func (list *CircularLinked) Cursor() *Node {
if list.cursor == nil {
list.cursor = list.head
}
return list.cursor
}
// CursorNext get next Cursor
func (list *CircularLinked) CursorNext() *Node {
list.cursor = list.Cursor().next
return list.cursor
}
// CursorPrev get prev Cursor
func (list *CircularLinked) CursorPrev() *Node {
list.cursor = list.Cursor().prev
return list.cursor
}
// CursorToHead cursor move to head
func (list *CircularLinked) CursorToHead() *Node {
list.cursor = list.head
return list.cursor
}
// CursorToTail cursor move to tail
func (list *CircularLinked) CursorToTail() *Node {
list.cursor = list.tail
return list.cursor
}
// Append a value (one or more) at the end of the list (same as Append())
func (list *CircularLinked) Append(values ...interface{}) {
for _, value := range values {
node := &Node{value: value}
if list.size == 0 {
list.head = node
list.tail = node
node.next = node
node.prev = node
} else {
list.tail.next = node
node.next = list.head
node.prev = list.tail
list.tail = node
}
list.size++
}
}
// Remove 移除一些节点
func (list *CircularLinked) Remove(node *Node) {
switch list.size {
case 0:
list.errorNotInList(node)
case 1:
if list.head == node {
list.head = nil
list.tail = nil
node.next = nil
node.prev = nil
list.cursor = nil
list.size--
} else {
list.errorNotInList(node)
}
case 2:
node.prev = nil
node.next = nil
switch node {
case list.head:
list.head = list.tail
list.tail.prev = list.head
list.head.next = list.tail
list.cursor = list.head
list.size--
case list.tail:
list.tail = list.head
list.tail.prev = list.head
list.head.next = list.tail
list.cursor = list.head
list.size--
default:
list.errorNotInList(node)
}
default:
switch node {
case list.head:
_, next := list.cutAndSplice(node)
list.size--
list.head = next
if list.cursor == node {
list.cursor = next
}
case list.tail:
prev, _ := list.cutAndSplice(node)
list.size--
list.tail = prev
if list.cursor == node {
list.cursor = prev
}
default:
_, next := list.cutAndSplice(node)
list.size--
if list.cursor == node {
list.cursor = next
}
}
}
}
// LookCursor for list show
func (list *CircularLinked) LookCursor() string {
cursor := list.Cursor()
content := "->["
cur := list.head
if list.size != 0 {
for size := uint64(0); size < list.size; size++ {
if cursor == cur {
content += "(" + spew.Sprint(cur.value) + ")" + ", "
} else {
content += spew.Sprint(cur.value) + ", "
}
cur = cur.next
}
}
content = strings.TrimRight(content, ", ")
showlen := len(content)
if showlen >= 64 {
showlen = 32
}
content += "]" + content[0:showlen] + " ..."
return content
}
// Clear for list show
func (list *CircularLinked) Clear() {
if list.size != 0 {
list.head.prev = nil
list.tail.next = nil
list.head = nil
list.tail = nil
list.cursor = nil
list.size = 0
}
}
// Size for list show
func (list *CircularLinked) Size() uint64 {
return list.size
}
func (list *CircularLinked) errorNotInList(node *Node) {
log.Println("the node value ", spew.Sprint(node), " is not in list")
}
func (list *CircularLinked) cutAndSplice(node *Node) (prev, next *Node) {
prev = node.prev
next = node.next
prev.next = next
next.prev = prev
node.prev = nil
node.next = nil
return prev, next
}

67
structure_test.go Normal file
View File

@ -0,0 +1,67 @@
package imitate
import (
"testing"
)
func TestCircularLinkedLookUp(t *testing.T) {
cl := NewCircularLinked(1, 2, 3, 4, 5, 6)
if !(cl.head.value.(int) == 1 && cl.tail.value.(int) == 6) {
t.Error(cl.LookCursor())
}
cl = NewCircularLinked(6, 2, 3, 4, 5, 1)
if !(cl.head.value.(int) == 6 && cl.tail.value.(int) == 1) {
t.Error("New List is error:", cl.LookCursor())
}
if cl.CursorNext().value.(int) != 2 {
t.Error("CursorNext error:", cl.LookCursor())
}
cl = NewCircularLinked(0, 1, 2, 3, 4, 5)
for i := 0; i < 6; i++ {
if cl.Cursor().value.(int) != i {
t.Error("CursorNext error:", cl.LookCursor())
}
cl.CursorNext()
}
for i := 0; i < 6; i++ {
if cl.Cursor().value.(int) != i {
t.Error("CursorNext loop error:", cl.LookCursor())
}
cl.CursorNext()
}
cl = NewCircularLinked(6, 2, 3, 4, 5, 1)
cl.Remove(cl.Cursor())
if cl.Cursor().value != 2 {
t.Error("Remove Head is error", cl.LookCursor())
}
cl.Remove(cl.CursorToTail())
if cl.Cursor().value != 5 {
t.Error("Remove CursorToTail is error", cl.LookCursor())
}
cl.Remove(cl.CursorToHead())
if cl.Cursor().value != 3 {
t.Error("Remove CursorToHead is error", cl.LookCursor())
}
limitCount := 0
for cl.Size() > 0 {
cl.Remove(cl.Cursor())
limitCount++
if limitCount >= 10 {
t.Error("Not Clear", cl.LookCursor())
break
}
}
cl.Remove(cl.CursorToHead()) // nil is not in list is success!
if cl.head != nil || cl.tail != nil || cl.cursor != nil {
t.Error("Remove Boundary error")
}
}

View File

@ -4,7 +4,8 @@ proxies : ["socks5://10.10.10.1:8080", "socks5://10.10.10.1:8082", "socks5://10.
retry : 0
priority : 10000
curl : "@test.curl"
# curls: "@test.curl"
curls : ["@test.curl", "curl 'https://segmentfault.com/a/1190000004850183' -H 'authority: segmentfault.com' -H 'cache-control: max-age=0' -H 'upgrade-insecure-requests: 1' -H 'user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: zh' -H 'cookie: _ga=GA1.2.923011700.1533555581; PHPSESSID=web1~3uf1ijg2h8nctqdof7aa27g1p8; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1542945905,1542945911,1542967158,1542969075; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1542969075' --compressed"]
# next_do : "doothers"