func LoadFromReader(in io.Reader) (c *ConfigFile, err error) {
	c = newConfigFile([]string{""})
	err = c.read(in)
	return c, err
}

func LoadFromReader ( in io . Reader ) ( c * ConfigFile , err error ) { c = newConfigFile ( [ ] string { " " } ) err = c . read ( in ) return c , err }

// LoadFromReader accepts raw data directly from a reader
// and returns a new configuration representation.
// You must use ReloadData to reload.
// You cannot append files a configfile read this way.

LoadFromReader accepts raw data directly from a reader and returns a new configuration representation . You must use ReloadData to reload . You cannot append files a configfile read this way .


func (c *ConfigFile) ReloadData(in io.Reader) (err error) {
	var cfg *ConfigFile
	if len(c.fileNames) != 1 {
		return fmt.Errorf("Multiple files loaded, unable to mix in-memory and file data")
	}

	cfg, err = LoadFromReader(in)
	if err == nil {
		*c = *cfg
	}
	return err
}

func ( c * ConfigFile ) ReloadData ( in io . Reader ) ( err error ) { var cfg * ConfigFile if len ( c . fileNames ) != 1 { return fmt . Errorf ( " " ) } cfg , err = LoadFromReader ( in ) if err == nil { * c = * cfg } return err }

// ReloadData reloads configuration file from memory


func (c *ConfigFile) AppendFiles(files ...string) error {
	if len(c.fileNames) == 1 && c.fileNames[0] == "" {
		return fmt.Errorf("Cannot append file data to in-memory data")
	}
	c.fileNames = append(c.fileNames, files...)
	return c.Reload()
}

func ( c * ConfigFile ) AppendFiles ( files ... string ) error { if len ( c . fileNames ) == 1 && c . fileNames [ 0 ] == " " { return fmt . Errorf ( " " ) } c . fileNames = append ( c . fileNames , files ... ) return c . Reload ( ) }

// AppendFiles appends more files to ConfigFile and reload automatically.

AppendFiles appends more files to ConfigFile and reload automatically .


func (c *ConfigFile) GetKeyList(section string) []string {
	// Blank section name represents DEFAULT section.
	if len(section) == 0 {
		section = DEFAULT_SECTION
	}

	if c.BlockMode {
		c.lock.RLock()
		defer c.lock.RUnlock()
	}

	// Check if section exists.
	if _, ok := c.data[section]; !ok {
		return nil
	}

	// Non-default section has a blank key as section keeper.
	list := make([]string, 0, len(c.keyList[section]))
	for _, key := range c.keyList[section] {
		if key != " " {
			list = append(list, key)
		}
	}
	return list
}

// GetKeyList returns the list of all keys in give section
// in the same order in the file.
// It returns nil if given section does not exist.

GetKeyList returns the list of all keys in give section in the same order in the file . It returns nil if given section does not exist .


func SaveConfigData(c *ConfigFile, out io.Writer) (err error) {
	equalSign := "="
	if PrettyFormat {
		equalSign = " = "
	}

	buf := bytes.NewBuffer(nil)
	for _, section := range c.sectionList {
		// Write section comments.
		if len(c.GetSectionComments(section)) > 0 {
			if _, err = buf.WriteString(c.GetSectionComments(section) + LineBreak); err != nil {
				return err
			}
		}

		if section != DEFAULT_SECTION {
			// Write section name.
			if _, err = buf.WriteString("[" + section + "]" + LineBreak); err != nil {
				return err
			}
		}

		for _, key := range c.keyList[section] {
			if key != " " {
				// Write key comments.
				if len(c.GetKeyComments(section, key)) > 0 {
					if _, err = buf.WriteString(c.GetKeyComments(section, key) + LineBreak); err != nil {
						return err
					}
				}

				keyName := key
				// Check if it's auto increment.
				if keyName[0] == '#' {
					keyName = "-"
				}
				//[SWH|+]:支持键名包含等号和冒号
				if strings.Contains(keyName, `=`) || strings.Contains(keyName, `:`) {
					if strings.Contains(keyName, "`") {
						if strings.Contains(keyName, `"`) {
							keyName = `"""` + keyName + `"""`
						} else {
							keyName = `"` + keyName + `"`
						}
					} else {
						keyName = "`" + keyName + "`"
					}
				}
				value := c.data[section][key]
				// In case key value contains "`" or "\"".
				if strings.Contains(value, "`") {
					if strings.Contains(value, `"`) {
						value = `"""` + value + `"""`
					} else {
						value = `"` + value + `"`
					}
				}

				// Write key and value.
				if _, err = buf.WriteString(keyName + equalSign + value + LineBreak); err != nil {
					return err
				}
			}
		}

		// Put a line between sections.
		if _, err = buf.WriteString(LineBreak); err != nil {
			return err
		}
	}

	if _, err := buf.WriteTo(out); err != nil {
		return err
	}
	return nil
}

//[SWH|+]:支持键名包含等号和冒号

// SaveConfigData writes configuration to a writer


func SaveConfigFile(c *ConfigFile, filename string) (err error) {
	// Write configuration file by filename.
	var f *os.File
	if f, err = os.Create(filename); err != nil {
		return err
	}

	if err := SaveConfigData(c, f); err != nil {
		return err
	}
	return f.Close()
}

// SaveConfigFile writes configuration file to local file system


func (s *selectable) Find(selector string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.CSS, selector).Single())
}

func ( s * selectable ) Find ( selector string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . CSS , selector ) . Single ( ) ) }

// Find finds exactly one element by CSS selector.

Find finds exactly one element by CSS selector .


func (s *selectable) FindByXPath(selector string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.XPath, selector).Single())
}

func ( s * selectable ) FindByXPath ( selector string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . XPath , selector ) . Single ( ) ) }

// FindByXPath finds exactly one element by XPath selector.

FindByXPath finds exactly one element by XPath selector .


func (s *selectable) FindByLink(text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Link, text).Single())
}

func ( s * selectable ) FindByLink ( text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Link , text ) . Single ( ) ) }

// FindByLink finds exactly one anchor element by its text content.

FindByLink finds exactly one anchor element by its text content .


func (s *selectable) FindByLabel(text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Label, text).Single())
}

func ( s * selectable ) FindByLabel ( text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Label , text ) . Single ( ) ) }

// FindByLabel finds exactly one element by associated label text.

FindByLabel finds exactly one element by associated label text .


func (s *selectable) FindByName(name string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Name, name).Single())
}

func ( s * selectable ) FindByName ( name string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Name , name ) . Single ( ) ) }

// FindByName finds exactly element with the provided name attribute.

FindByName finds exactly element with the provided name attribute .


func (s *selectable) FindByClass(text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Class, text).Single())
}

func ( s * selectable ) FindByClass ( text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Class , text ) . Single ( ) ) }

// FindByClass finds exactly one element with a given CSS class.

FindByClass finds exactly one element with a given CSS class .


func (s *selectable) FindByID(id string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.ID, id).Single())
}

func ( s * selectable ) FindByID ( id string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . ID , id ) . Single ( ) ) }

// FindByID finds exactly one element that has the given ID.

FindByID finds exactly one element that has the given ID .


func (s *selectable) First(selector string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.CSS, selector).At(0))
}

func ( s * selectable ) First ( selector string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . CSS , selector ) . At ( 0 ) ) }

// First finds the first element by CSS selector.

First finds the first element by CSS selector .


func (s *selectable) FirstByXPath(selector string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.XPath, selector).At(0))
}

func ( s * selectable ) FirstByXPath ( selector string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . XPath , selector ) . At ( 0 ) ) }

// FirstByXPath finds the first element by XPath selector.

FirstByXPath finds the first element by XPath selector .


func (s *selectable) FirstByLink(text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Link, text).At(0))
}

func ( s * selectable ) FirstByLink ( text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Link , text ) . At ( 0 ) ) }

// FirstByLink finds the first anchor element by its text content.

FirstByLink finds the first anchor element by its text content .


func (s *selectable) FirstByLabel(text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Label, text).At(0))
}

func ( s * selectable ) FirstByLabel ( text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Label , text ) . At ( 0 ) ) }

// FirstByLabel finds the first element by associated label text.

FirstByLabel finds the first element by associated label text .


func (s *selectable) FirstByName(name string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Name, name).At(0))
}

func ( s * selectable ) FirstByName ( name string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Name , name ) . At ( 0 ) ) }

// FirstByName finds the first element with the provided name attribute.

FirstByName finds the first element with the provided name attribute .


func (s *selectable) All(selector string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.CSS, selector))
}

func ( s * selectable ) All ( selector string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . CSS , selector ) ) }

// All finds zero or more elements by CSS selector.

All finds zero or more elements by CSS selector .


func (s *selectable) AllByXPath(selector string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.XPath, selector))
}

func ( s * selectable ) AllByXPath ( selector string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . XPath , selector ) ) }

// AllByXPath finds zero or more elements by XPath selector.

AllByXPath finds zero or more elements by XPath selector .


func (s *selectable) AllByLink(text string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.Link, text))
}

func ( s * selectable ) AllByLink ( text string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . Link , text ) ) }

// AllByLink finds zero or more anchor elements by their text content.

AllByLink finds zero or more anchor elements by their text content .


func (s *selectable) AllByLabel(text string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.Label, text))
}

func ( s * selectable ) AllByLabel ( text string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . Label , text ) ) }

// AllByLabel finds zero or more elements by associated label text.

AllByLabel finds zero or more elements by associated label text .


func (s *selectable) AllByName(name string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.Name, name))
}

func ( s * selectable ) AllByName ( name string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . Name , name ) ) }

// AllByName finds zero or more elements with the provided name attribute.

AllByName finds zero or more elements with the provided name attribute .


func (s *selectable) AllByClass(text string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.Class, text))
}

func ( s * selectable ) AllByClass ( text string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . Class , text ) ) }

// AllByClass finds zero or more elements with a given CSS class.

AllByClass finds zero or more elements with a given CSS class .


func (s *selectable) AllByID(text string) *MultiSelection {
	return newMultiSelection(s.session, s.selectors.Append(target.ID, text))
}

func ( s * selectable ) AllByID ( text string ) * MultiSelection { return newMultiSelection ( s . session , s . selectors . Append ( target . ID , text ) ) }

// AllByID finds zero or more elements with a given ID.

AllByID finds zero or more elements with a given ID .


func (s *selectable) FindForAppium(selectorType string, text string) *Selection {
	return newSelection(s.session, s.selectors.Append(target.Class, text).At(0))
}

func ( s * selectable ) FindForAppium ( selectorType string , text string ) * Selection { return newSelection ( s . session , s . selectors . Append ( target . Class , text ) . At ( 0 ) ) }

// FirstByClass finds the first element with a given CSS class.

FirstByClass finds the first element with a given CSS class .


func Timeout(seconds int) Option {
	return func(c *config) {
		c.Timeout = time.Duration(seconds) * time.Second
	}
}

func Timeout ( seconds int ) Option { return func ( c * config ) { c . Timeout = time . Duration ( seconds ) * time . Second } }

// Timeout provides an Option for specifying a timeout in seconds.

Timeout provides an Option for specifying a timeout in seconds .


func ChromeOptions(opt string, value interface{}) Option {
	return func(c *config) {
		if c.ChromeOptions == nil {
			c.ChromeOptions = make(map[string]interface{})
		}
		c.ChromeOptions[opt] = value
	}
}

func ChromeOptions ( opt string , value interface { } ) Option { return func ( c * config ) { if c . ChromeOptions == nil { c . ChromeOptions = make ( map [ string ] interface { } ) } c . ChromeOptions [ opt ] = value } }

// ChromeOptions is used to pass additional options to Chrome via ChromeDriver.

ChromeOptions is used to pass additional options to Chrome via ChromeDriver .


func JoinPage(url string, options ...Option) *Page {
	pageOptions := config{}.Merge(options)
	session := api.NewWithClient(url, pageOptions.HTTPClient)
	return newPage(session)
}

func JoinPage ( url string , options ... Option ) * Page { pageOptions := config { } . Merge ( options ) session := api . NewWithClient ( url , pageOptions . HTTPClient ) return newPage ( session ) }

// JoinPage creates a Page using existing session URL. This method takes Options
// but respects only the HTTPClient Option if provided.

JoinPage creates a Page using existing session URL . This method takes Options but respects only the HTTPClient Option if provided .


func (p *Page) Destroy() error {
	if err := p.session.Delete(); err != nil {
		return fmt.Errorf("failed to destroy session: %s", err)
	}
	return nil
}

func ( p * Page ) Destroy ( ) error { if err := p . session . Delete ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// Destroy closes any open browsers by ending the session.

Destroy closes any open browsers by ending the session .


func (p *Page) Reset() error {
	p.ConfirmPopup()

	url, err := p.URL()
	if err != nil {
		return err
	}
	if url == "about:blank" {
		return nil
	}

	if err := p.ClearCookies(); err != nil {
		return err
	}

	if err := p.session.DeleteLocalStorage(); err != nil {
		if err := p.RunScript("localStorage.clear();", nil, nil); err != nil {
			return err
		}
	}

	if err := p.session.DeleteSessionStorage(); err != nil {
		if err := p.RunScript("sessionStorage.clear();", nil, nil); err != nil {
			return err
		}
	}

	return p.Navigate("about:blank")
}

func ( p * Page ) Reset ( ) error { p . ConfirmPopup ( ) url , err := p . URL ( ) if err != nil { return err } if url == " " { return nil } if err := p . ClearCookies ( ) ; err != nil { return err } if err := p . session . DeleteLocalStorage ( ) ; err != nil { if err := p . RunScript ( " " , nil , nil ) ; err != nil { return err } } if err := p . session . DeleteSessionStorage ( ) ; err != nil { if err := p . RunScript ( " " , nil , nil ) ; err != nil { return err } } return p . Navigate ( " " ) }

// Reset deletes all cookies set for the current domain and navigates to a blank page.
// Unlike Destroy, Reset will permit the page to be re-used after it is called.
// Reset is faster than Destroy, but any cookies from domains outside the current
// domain will remain after a page is reset.

Reset deletes all cookies set for the current domain and navigates to a blank page . Unlike Destroy Reset will permit the page to be re - used after it is called . Reset is faster than Destroy but any cookies from domains outside the current domain will remain after a page is reset .


func (p *Page) Navigate(url string) error {
	if err := p.session.SetURL(url); err != nil {
		return fmt.Errorf("failed to navigate: %s", err)
	}
	return nil
}

func ( p * Page ) Navigate ( url string ) error { if err := p . session . SetURL ( url ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// Navigate navigates to the provided URL.

Navigate navigates to the provided URL .


func (p *Page) GetCookies() ([]*http.Cookie, error) {
	apiCookies, err := p.session.GetCookies()
	if err != nil {
		return nil, fmt.Errorf("failed to get cookies: %s", err)
	}
	cookies := []*http.Cookie{}
	for _, apiCookie := range apiCookies {
		expSeconds := int64(apiCookie.Expiry)
		expNano := int64(apiCookie.Expiry-float64(expSeconds)) * 1000000000
		cookie := &http.Cookie{
			Name:     apiCookie.Name,
			Value:    apiCookie.Value,
			Path:     apiCookie.Path,
			Domain:   apiCookie.Domain,
			Secure:   apiCookie.Secure,
			HttpOnly: apiCookie.HTTPOnly,
			Expires:  time.Unix(expSeconds, expNano),
		}
		cookies = append(cookies, cookie)
	}
	return cookies, nil
}

func ( p * Page ) GetCookies ( ) ( [ ] * http . Cookie , error ) { apiCookies , err := p . session . GetCookies ( ) if err != nil { return nil , fmt . Errorf ( " " , err ) } cookies := [ ] * http . Cookie { } for _ , apiCookie := range apiCookies { expSeconds := int64 ( apiCookie . Expiry ) expNano := int64 ( apiCookie . Expiry - float64 ( expSeconds ) ) * 1000000000 cookie := & http . Cookie { Name : apiCookie . Name , Value : apiCookie . Value , Path : apiCookie . Path , Domain : apiCookie . Domain , Secure : apiCookie . Secure , HttpOnly : apiCookie . HTTPOnly , Expires : time . Unix ( expSeconds , expNano ) , } cookies = append ( cookies , cookie ) } return cookies , nil }

// GetCookies returns all cookies on the page.

GetCookies returns all cookies on the page .


func (p *Page) SetCookie(cookie *http.Cookie) error {
	if cookie == nil {
		return errors.New("nil cookie is invalid")
	}

	var expiry int64
	if !cookie.Expires.IsZero() {
		expiry = cookie.Expires.Unix()
	}

	apiCookie := &api.Cookie{
		Name:     cookie.Name,
		Value:    cookie.Value,
		Path:     cookie.Path,
		Domain:   cookie.Domain,
		Secure:   cookie.Secure,
		HTTPOnly: cookie.HttpOnly,
		Expiry:   float64(expiry),
	}

	if err := p.session.SetCookie(apiCookie); err != nil {
		return fmt.Errorf("failed to set cookie: %s", err)
	}
	return nil
}

func ( p * Page ) SetCookie ( cookie * http . Cookie ) error { if cookie == nil { return errors . New ( " " ) } var expiry int64 if ! cookie . Expires . IsZero ( ) { expiry = cookie . Expires . Unix ( ) } apiCookie := & api . Cookie { Name : cookie . Name , Value : cookie . Value , Path : cookie . Path , Domain : cookie . Domain , Secure : cookie . Secure , HTTPOnly : cookie . HttpOnly , Expiry : float64 ( expiry ) , } if err := p . session . SetCookie ( apiCookie ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }


func (p *Page) DeleteCookie(name string) error {
	if err := p.session.DeleteCookie(name); err != nil {
		return fmt.Errorf("failed to delete cookie %s: %s", name, err)
	}
	return nil
}

func ( p * Page ) DeleteCookie ( name string ) error { if err := p . session . DeleteCookie ( name ) ; err != nil { return fmt . Errorf ( " " , name , err ) } return nil }

// DeleteCookie deletes a cookie on the page by name.

DeleteCookie deletes a cookie on the page by name .


func (p *Page) ClearCookies() error {
	if err := p.session.DeleteCookies(); err != nil {
		return fmt.Errorf("failed to clear cookies: %s", err)
	}
	return nil
}

func ( p * Page ) ClearCookies ( ) error { if err := p . session . DeleteCookies ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// ClearCookies deletes all cookies on the page.

ClearCookies deletes all cookies on the page .


func (p *Page) URL() (string, error) {
	url, err := p.session.GetURL()
	if err != nil {
		return "", fmt.Errorf("failed to retrieve URL: %s", err)
	}
	return url, nil
}

func ( p * Page ) URL ( ) ( string , error ) { url , err := p . session . GetURL ( ) if err != nil { return " " , fmt . Errorf ( " " , err ) } return url , nil }


func (p *Page) Size(width, height int) error {
	window, err := p.session.GetWindow()
	if err != nil {
		return fmt.Errorf("failed to retrieve window: %s", err)
	}

	if err := window.SetSize(width, height); err != nil {
		return fmt.Errorf("failed to set window size: %s", err)
	}

	return nil
}

func ( p * Page ) Size ( width , height int ) error { window , err := p . session . GetWindow ( ) if err != nil { return fmt . Errorf ( " " , err ) } if err := window . SetSize ( width , height ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// Size sets the current page size in pixels.

Size sets the current page size in pixels .


func (p *Page) Screenshot(filename string) error {
	absFilePath, err := filepath.Abs(filename)
	if err != nil {
		return fmt.Errorf("failed to find absolute path for filename: %s", err)
	}

	screenshot, err := p.session.GetScreenshot()
	if err != nil {
		return fmt.Errorf("failed to retrieve screenshot: %s", err)
	}

	if err := ioutil.WriteFile(absFilePath, screenshot, 0666); err != nil {
		return fmt.Errorf("failed to save screenshot: %s", err)
	}

	return nil
}

func ( p * Page ) Screenshot ( filename string ) error { absFilePath , err := filepath . Abs ( filename ) if err != nil { return fmt . Errorf ( " " , err ) } screenshot , err := p . session . GetScreenshot ( ) if err != nil { return fmt . Errorf ( " " , err ) } if err := ioutil . WriteFile ( absFilePath , screenshot , 0666 ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// Screenshot takes a screenshot and saves it to the provided filename.
// The provided filename may be an absolute or relative path.

Screenshot takes a screenshot and saves it to the provided filename . The provided filename may be an absolute or relative path .


func (p *Page) Title() (string, error) {
	title, err := p.session.GetTitle()
	if err != nil {
		return "", fmt.Errorf("failed to retrieve page title: %s", err)
	}
	return title, nil
}

func ( p * Page ) Title ( ) ( string , error ) { title , err := p . session . GetTitle ( ) if err != nil { return " " , fmt . Errorf ( " " , err ) } return title , nil }


func (p *Page) HTML() (string, error) {
	html, err := p.session.GetSource()
	if err != nil {
		return "", fmt.Errorf("failed to retrieve page HTML: %s", err)
	}
	return html, nil
}

func ( p * Page ) HTML ( ) ( string , error ) { html , err := p . session . GetSource ( ) if err != nil { return " " , fmt . Errorf ( " " , err ) } return html , nil }

// HTML returns the current contents of the DOM for the entire page.

HTML returns the current contents of the DOM for the entire page .


func (p *Page) PopupText() (string, error) {
	text, err := p.session.GetAlertText()
	if err != nil {
		return "", fmt.Errorf("failed to retrieve popup text: %s", err)
	}
	return text, nil
}

func ( p * Page ) PopupText ( ) ( string , error ) { text , err := p . session . GetAlertText ( ) if err != nil { return " " , fmt . Errorf ( " " , err ) } return text , nil }

// PopupText returns the current alert, confirm, or prompt popup text.

PopupText returns the current alert confirm or prompt popup text .


func (p *Page) EnterPopupText(text string) error {
	if err := p.session.SetAlertText(text); err != nil {
		return fmt.Errorf("failed to enter popup text: %s", err)
	}
	return nil
}

func ( p * Page ) EnterPopupText ( text string ) error { if err := p . session . SetAlertText ( text ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// EnterPopupText enters text into an open prompt popup.

EnterPopupText enters text into an open prompt popup .


func (p *Page) ConfirmPopup() error {
	if err := p.session.AcceptAlert(); err != nil {
		return fmt.Errorf("failed to confirm popup: %s", err)
	}
	return nil
}

func ( p * Page ) ConfirmPopup ( ) error { if err := p . session . AcceptAlert ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// ConfirmPopup confirms an alert, confirm, or prompt popup.

ConfirmPopup confirms an alert confirm or prompt popup .


func (p *Page) CancelPopup() error {
	if err := p.session.DismissAlert(); err != nil {
		return fmt.Errorf("failed to cancel popup: %s", err)
	}
	return nil
}

func ( p * Page ) CancelPopup ( ) error { if err := p . session . DismissAlert ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// CancelPopup cancels an alert, confirm, or prompt popup.

CancelPopup cancels an alert confirm or prompt popup .


func (p *Page) SwitchToParentFrame() error {
	if err := p.session.FrameParent(); err != nil {
		return fmt.Errorf("failed to switch to parent frame: %s", err)
	}
	return nil
}

func ( p * Page ) SwitchToParentFrame ( ) error { if err := p . session . FrameParent ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// SwitchToParentFrame focuses on the immediate parent frame of a frame selected
// by Selection.Frame. After switching, all new and existing selections will refer
// to the parent frame. All further Page methods will apply to this frame as well.
//
// This method is not supported by PhantomJS. Please use SwitchToRootFrame instead.

SwitchToParentFrame focuses on the immediate parent frame of a frame selected by Selection . Frame . After switching all new and existing selections will refer to the parent frame . All further Page methods will apply to this frame as well . This method is not supported by PhantomJS . Please use SwitchToRootFrame instead .


func (p *Page) SwitchToRootFrame() error {
	if err := p.session.Frame(nil); err != nil {
		return fmt.Errorf("failed to switch to original page frame: %s", err)
	}
	return nil
}

func ( p * Page ) SwitchToRootFrame ( ) error { if err := p . session . Frame ( nil ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// SwitchToRootFrame focuses on the original, default page frame before any calls
// to Selection.Frame were made. After switching, all new and existing selections
// will refer to the root frame. All further Page methods will apply to this frame
// as well.

SwitchToRootFrame focuses on the original default page frame before any calls to Selection . Frame were made . After switching all new and existing selections will refer to the root frame . All further Page methods will apply to this frame as well .


func (p *Page) NextWindow() error {
	windows, err := p.session.GetWindows()
	if err != nil {
		return fmt.Errorf("failed to find available windows: %s", err)
	}

	var windowIDs []string
	for _, window := range windows {
		windowIDs = append(windowIDs, window.ID)
	}

	// order not defined according to W3 spec
	sort.Strings(windowIDs)

	activeWindow, err := p.session.GetWindow()
	if err != nil {
		return fmt.Errorf("failed to find active window: %s", err)
	}

	for position, windowID := range windowIDs {
		if windowID == activeWindow.ID {
			activeWindow.ID = windowIDs[(position+1)%len(windowIDs)]
			break
		}
	}

	if err := p.session.SetWindow(activeWindow); err != nil {
		return fmt.Errorf("failed to change active window: %s", err)
	}

	return nil
}

// NextWindow switches to the next available window.

NextWindow switches to the next available window .


func (p *Page) CloseWindow() error {
	if err := p.session.DeleteWindow(); err != nil {
		return fmt.Errorf("failed to close active window: %s", err)
	}
	return nil
}

func ( p * Page ) CloseWindow ( ) error { if err := p . session . DeleteWindow ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// CloseWindow closes the active window.


func (p *Page) WindowCount() (int, error) {
	windows, err := p.session.GetWindows()
	if err != nil {
		return 0, fmt.Errorf("failed to find available windows: %s", err)
	}
	return len(windows), nil
}

func ( p * Page ) WindowCount ( ) ( int , error ) { windows , err := p . session . GetWindows ( ) if err != nil { return 0 , fmt . Errorf ( " " , err ) } return len ( windows ) , nil }

// WindowCount returns the number of available windows.

WindowCount returns the number of available windows .


func (p *Page) LogTypes() ([]string, error) {
	types, err := p.session.GetLogTypes()
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve log types: %s", err)
	}
	return types, nil
}

func ( p * Page ) LogTypes ( ) ( [ ] string , error ) { types , err := p . session . GetLogTypes ( ) if err != nil { return nil , fmt . Errorf ( " " , err ) } return types , nil }

// LogTypes returns all of the valid log types that may be used with a LogReader.

LogTypes returns all of the valid log types that may be used with a LogReader .


func (p *Page) MoveMouseBy(xOffset, yOffset int) error {
	if err := p.session.MoveTo(nil, api.XYOffset{X: xOffset, Y: yOffset}); err != nil {
		return fmt.Errorf("failed to move mouse: %s", err)
	}

	return nil
}

func ( p * Page ) MoveMouseBy ( xOffset , yOffset int ) error { if err := p . session . MoveTo ( nil , api . XYOffset { X : xOffset , Y : yOffset } ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// MoveMouseBy moves the mouse by the provided offset.

MoveMouseBy moves the mouse by the provided offset .


func (p *Page) DoubleClick() error {
	if err := p.session.DoubleClick(); err != nil {
		return fmt.Errorf("failed to double click: %s", err)
	}

	return nil
}

func ( p * Page ) DoubleClick ( ) error { if err := p . session . DoubleClick ( ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// DoubleClick double clicks the left mouse button at the current mouse
// position.

DoubleClick double clicks the left mouse button at the current mouse position .


func (p *Page) Click(event Click, button Button) error {
	var err error
	switch event {
	case SingleClick:
		err = p.session.Click(api.Button(button))
	case HoldClick:
		err = p.session.ButtonDown(api.Button(button))
	case ReleaseClick:
		err = p.session.ButtonUp(api.Button(button))
	default:
		err = errors.New("invalid touch event")
	}
	if err != nil {
		return fmt.Errorf("failed to %s %s: %s", event, button, err)
	}

	return nil
}

func ( p * Page ) Click ( event Click , button Button ) error { var err error switch event { case SingleClick : err = p . session . Click ( api . Button ( button ) ) case HoldClick : err = p . session . ButtonDown ( api . Button ( button ) ) case ReleaseClick : err = p . session . ButtonUp ( api . Button ( button ) ) default : err = errors . New ( " " ) } if err != nil { return fmt . Errorf ( " " , event , button , err ) } return nil }

// Click performs the provided Click event using the provided Button at the
// current mouse position.

Click performs the provided Click event using the provided Button at the current mouse position .


func (s *Selection) Click() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Click(); err != nil {
			return fmt.Errorf("failed to click on %s: %s", s, err)
		}
		return nil
	})
}

func ( s * Selection ) Click ( ) error { return s . forEachElement ( func ( selectedElement element . Element ) error { if err := selectedElement . Click ( ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil } ) }

// Click clicks on all of the elements that the selection refers to.

Click clicks on all of the elements that the selection refers to .


func (s *Selection) DoubleClick() error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := s.session.MoveTo(selectedElement.(*api.Element), nil); err != nil {
			return fmt.Errorf("failed to move mouse to %s: %s", s, err)
		}
		if err := s.session.DoubleClick(); err != nil {
			return fmt.Errorf("failed to double-click on %s: %s", s, err)
		}
		return nil
	})
}

func ( s * Selection ) DoubleClick ( ) error { return s . forEachElement ( func ( selectedElement element . Element ) error { if err := s . session . MoveTo ( selectedElement . ( * api . Element ) , nil ) ; err != nil { return fmt . Errorf ( " " , s , err ) } if err := s . session . DoubleClick ( ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil } ) }

// DoubleClick double-clicks on all of the elements that the selection refers to.

DoubleClick double - clicks on all of the elements that the selection refers to .


func (s *Selection) Fill(text string) error {
	return s.forEachElement(func(selectedElement element.Element) error {
		if err := selectedElement.Clear(); err != nil {
			return fmt.Errorf("failed to clear %s: %s", s, err)
		}
		if err := selectedElement.Value(text); err != nil {
			return fmt.Errorf("failed to enter text into %s: %s", s, err)
		}
		return nil
	})
}

func ( s * Selection ) Fill ( text string ) error { return s . forEachElement ( func ( selectedElement element . Element ) error { if err := selectedElement . Clear ( ) ; err != nil { return fmt . Errorf ( " " , s , err ) } if err := selectedElement . Value ( text ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil } ) }

// Fill fills all of the fields the selection refers to with the provided text.

Fill fills all of the fields the selection refers to with the provided text .


func (s *Selection) Tap(event Tap) error {
	var touchFunc func(*api.Element) error
	switch event {
	case SingleTap:
		touchFunc = s.session.TouchClick
	case DoubleTap:
		touchFunc = s.session.TouchDoubleClick
	case LongTap:
		touchFunc = s.session.TouchLongClick
	default:
		return fmt.Errorf("failed to %s on %s: invalid tap event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		if err := touchFunc(selectedElement.(*api.Element)); err != nil {
			return fmt.Errorf("failed to %s on %s: %s", event, s, err)
		}
		return nil
	})
}

func ( s * Selection ) Tap ( event Tap ) error { var touchFunc func ( * api . Element ) error switch event { case SingleTap : touchFunc = s . session . TouchClick case DoubleTap : touchFunc = s . session . TouchDoubleClick case LongTap : touchFunc = s . session . TouchLongClick default : return fmt . Errorf ( " " , event , s ) } return s . forEachElement ( func ( selectedElement element . Element ) error { if err := touchFunc ( selectedElement . ( * api . Element ) ) ; err != nil { return fmt . Errorf ( " " , event , s , err ) } return nil } ) }

// Tap performs the provided Tap event on each element in the selection.

Tap performs the provided Tap event on each element in the selection .


func (s *Selection) Touch(event Touch) error {
	var touchFunc func(x, y int) error
	switch event {
	case HoldFinger:
		touchFunc = s.session.TouchDown
	case ReleaseFinger:
		touchFunc = s.session.TouchUp
	case MoveFinger:
		touchFunc = s.session.TouchMove
	default:
		return fmt.Errorf("failed to %s on %s: invalid touch event", event, s)
	}

	return s.forEachElement(func(selectedElement element.Element) error {
		x, y, err := selectedElement.GetLocation()
		if err != nil {
			return fmt.Errorf("failed to retrieve location of %s: %s", s, err)
		}
		if err := touchFunc(x, y); err != nil {
			return fmt.Errorf("failed to flick finger on %s: %s", s, err)
		}
		return nil
	})
}

func ( s * Selection ) Touch ( event Touch ) error { var touchFunc func ( x , y int ) error switch event { case HoldFinger : touchFunc = s . session . TouchDown case ReleaseFinger : touchFunc = s . session . TouchUp case MoveFinger : touchFunc = s . session . TouchMove default : return fmt . Errorf ( " " , event , s ) } return s . forEachElement ( func ( selectedElement element . Element ) error { x , y , err := selectedElement . GetLocation ( ) if err != nil { return fmt . Errorf ( " " , s , err ) } if err := touchFunc ( x , y ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil } ) }

// Touch performs the provided Touch event at the location of each element in the
// selection.

Touch performs the provided Touch event at the location of each element in the selection .


func (s *Selection) FlickFinger(xOffset, yOffset int, speed uint) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchFlick(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}, api.ScalarSpeed(speed)); err != nil {
		return fmt.Errorf("failed to flick finger on %s: %s", s, err)
	}
	return nil
}

func ( s * Selection ) FlickFinger ( xOffset , yOffset int , speed uint ) error { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return fmt . Errorf ( " " , s , err ) } if err := s . session . TouchFlick ( selectedElement . ( * api . Element ) , api . XYOffset { X : xOffset , Y : yOffset } , api . ScalarSpeed ( speed ) ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil }

// FlickFinger performs a flick touch action by the provided offset and at the
// provided speed on exactly one element.

FlickFinger performs a flick touch action by the provided offset and at the provided speed on exactly one element .


func (s *Selection) ScrollFinger(xOffset, yOffset int) error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.TouchScroll(selectedElement.(*api.Element), api.XYOffset{X: xOffset, Y: yOffset}); err != nil {
		return fmt.Errorf("failed to scroll finger on %s: %s", s, err)
	}
	return nil
}

func ( s * Selection ) ScrollFinger ( xOffset , yOffset int ) error { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return fmt . Errorf ( " " , s , err ) } if err := s . session . TouchScroll ( selectedElement . ( * api . Element ) , api . XYOffset { X : xOffset , Y : yOffset } ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil }

// ScrollFinger performs a scroll touch action by the provided offset on exactly
// one element.

ScrollFinger performs a scroll touch action by the provided offset on exactly one element .


func NewCapabilities(features ...string) Capabilities {
	c := Capabilities{}
	for _, feature := range features {
		c.With(feature)
	}
	return c
}

func NewCapabilities ( features ... string ) Capabilities { c := Capabilities { } for _ , feature := range features { c . With ( feature ) } return c }

// NewCapabilities returns a Capabilities instance with any provided features enabled.

NewCapabilities returns a Capabilities instance with any provided features enabled .


func (c Capabilities) JSON() (string, error) {
	capabilitiesJSON, err := json.Marshal(c)
	return string(capabilitiesJSON), err
}

func ( c Capabilities ) JSON ( ) ( string , error ) { capabilitiesJSON , err := json . Marshal ( c ) return string ( capabilitiesJSON ) , err }

// JSON returns a JSON string representing the desired capabilities.

JSON returns a JSON string representing the desired capabilities .


func HaveTitle(title string) types.GomegaMatcher {
	return &internal.ValueMatcher{Method: "Title", Property: "title", Expected: title}
}

func HaveTitle ( title string ) types . GomegaMatcher { return & internal . ValueMatcher { Method : " " , Property : " " , Expected : title } }

// HaveTitle passes when the expected title is equivalent to the
// title of the provided page.

HaveTitle passes when the expected title is equivalent to the title of the provided page .


func HaveURL(url string) types.GomegaMatcher {
	return &internal.ValueMatcher{Method: "URL", Property: "URL", Expected: url}
}

func HaveURL ( url string ) types . GomegaMatcher { return & internal . ValueMatcher { Method : " " , Property : " " , Expected : url } }

// HaveURL passes when the expected URL is equivalent to the
// current URL of the provided page.

HaveURL passes when the expected URL is equivalent to the current URL of the provided page .


func HavePopupText(text string) types.GomegaMatcher {
	return &internal.ValueMatcher{Method: "PopupText", Property: "popup text", Expected: text}
}

func HavePopupText ( text string ) types . GomegaMatcher { return & internal . ValueMatcher { Method : " " , Property : " " , Expected : text } }

// HavePopupText passes when the expected text is equivalent to the
// text contents of an open alert, confirm, or prompt popup.

HavePopupText passes when the expected text is equivalent to the text contents of an open alert confirm or prompt popup .


func HaveLoggedError(messages ...string) types.GomegaMatcher {
	return &internal.LogMatcher{
		ExpectedMessages: messages,
		Levels:           []string{"WARNING", "SEVERE"},
		Name:             "error",
		Type:             "browser",
	}
}

func HaveLoggedError ( messages ... string ) types . GomegaMatcher { return & internal . LogMatcher { ExpectedMessages : messages , Levels : [ ] string { " " , " " } , Name : " " , Type : " " , } }

// HaveLoggedError passes when all of the expected log messages are logged as
// errors in the browser console. If no message is provided, this matcher will
// pass if any error message has been logged. When negated, this matcher will
// only fail if all of the provided messages are logged.

HaveLoggedError passes when all of the expected log messages are logged as errors in the browser console . If no message is provided this matcher will pass if any error message has been logged . When negated this matcher will only fail if all of the provided messages are logged .


func (s *Selection) Text() (string, error) {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return "", fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	text, err := selectedElement.GetText()
	if err != nil {
		return "", fmt.Errorf("failed to retrieve text for %s: %s", s, err)
	}
	return text, nil
}

func ( s * Selection ) Text ( ) ( string , error ) { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return " " , fmt . Errorf ( " " , s , err ) } text , err := selectedElement . GetText ( ) if err != nil { return " " , fmt . Errorf ( " " , s , err ) } return text , nil }

// Text returns the entirety of the text content for exactly one element.

Text returns the entirety of the text content for exactly one element .


func (s *Selection) Active() (bool, error) {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return false, fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	activeElement, err := s.session.GetActiveElement()
	if err != nil {
		return false, fmt.Errorf("failed to retrieve active element: %s", err)
	}

	equal, err := selectedElement.IsEqualTo(activeElement)
	if err != nil {
		return false, fmt.Errorf("failed to compare selection to active element: %s", err)
	}

	return equal, nil
}

func ( s * Selection ) Active ( ) ( bool , error ) { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return false , fmt . Errorf ( " " , s , err ) } activeElement , err := s . session . GetActiveElement ( ) if err != nil { return false , fmt . Errorf ( " " , err ) } equal , err := selectedElement . IsEqualTo ( activeElement ) if err != nil { return false , fmt . Errorf ( " " , err ) } return equal , nil }

// Active returns true if the single element that the selection refers to is active.

Active returns true if the single element that the selection refers to is active .


func (s *Selection) Attribute(attribute string) (string, error) {
	return s.hasProperty(element.Element.GetAttribute, attribute, "attribute")
}

func ( s * Selection ) Attribute ( attribute string ) ( string , error ) { return s . hasProperty ( element . Element . GetAttribute , attribute , " " ) }

// Attribute returns an attribute value for exactly one element.

Attribute returns an attribute value for exactly one element .


func (s *Selection) CSS(property string) (string, error) {
	return s.hasProperty(element.Element.GetCSS, property, "CSS property")
}

func ( s * Selection ) CSS ( property string ) ( string , error ) { return s . hasProperty ( element . Element . GetCSS , property , " " ) }

// CSS returns a CSS style property value for exactly one element.

CSS returns a CSS style property value for exactly one element .


func (s *Selection) Selected() (bool, error) {
	return s.hasState(element.Element.IsSelected, "selected")
}

func ( s * Selection ) Selected ( ) ( bool , error ) { return s . hasState ( element . Element . IsSelected , " " ) }

// Selected returns true if all of the elements that the selection refers to are selected.

Selected returns true if all of the elements that the selection refers to are selected .


func (s *Selection) Visible() (bool, error) {
	return s.hasState(element.Element.IsDisplayed, "visible")
}

func ( s * Selection ) Visible ( ) ( bool , error ) { return s . hasState ( element . Element . IsDisplayed , " " ) }

// Visible returns true if all of the elements that the selection refers to are visible.

Visible returns true if all of the elements that the selection refers to are visible .


func (s *Selection) Enabled() (bool, error) {
	return s.hasState(element.Element.IsEnabled, "enabled")
}

func ( s * Selection ) Enabled ( ) ( bool , error ) { return s . hasState ( element . Element . IsEnabled , " " ) }

// Enabled returns true if all of the elements that the selection refers to are enabled.

Enabled returns true if all of the elements that the selection refers to are enabled .


func HaveCount(count int) types.GomegaMatcher {
	return &internal.ValueMatcher{Method: "Count", Property: "element count", Expected: count}
}

func HaveCount ( count int ) types . GomegaMatcher { return & internal . ValueMatcher { Method : " " , Property : " " , Expected : count } }

// HaveCount passes when the expected element count is equal to the actual
// number of elements in the selection.

HaveCount passes when the expected element count is equal to the actual number of elements in the selection .


func HaveAttribute(attribute string, value string) types.GomegaMatcher {
	return &internal.HaveAttributeMatcher{ExpectedAttribute: attribute, ExpectedValue: value}
}

func HaveAttribute ( attribute string , value string ) types . GomegaMatcher { return & internal . HaveAttributeMatcher { ExpectedAttribute : attribute , ExpectedValue : value } }

// HaveAttribute passes when the expected attribute and value are present on the element.
// This matcher will fail if the provided selection refers to more than one element.

HaveAttribute passes when the expected attribute and value are present on the element . This matcher will fail if the provided selection refers to more than one element .


func EdgeDriver(options ...Option) *WebDriver {
	var binaryName string
	if runtime.GOOS == "windows" {
		binaryName = "MicrosoftWebDriver.exe"
	} else {
		return nil
	}
	command := []string{binaryName, "--port={{.Port}}"}
	// Using {{.Address}} means using 127.0.0.1
	// But MicrosoftWebDriver only supports localhost, not 127.0.0.1
	return NewWebDriver("http://localhost:{{.Port}}", command, options...)
}

// EdgeDriver returns an instance of a EdgeDriver WebDriver.
//
// Provided Options will apply as default arguments for new pages.
// New pages will accept invalid SSL certificates by default. This
// may be disabled using the RejectInvalidSSL Option.

EdgeDriver returns an instance of a EdgeDriver WebDriver . Provided Options will apply as default arguments for new pages . New pages will accept invalid SSL certificates by default . This may be disabled using the RejectInvalidSSL Option .


func Selendroid(jarFile string, options ...Option) *WebDriver {
	absJARPath, err := filepath.Abs(jarFile)
	if err != nil {
		return nil
	}

	command := []string{
		"java",
		"-jar", absJARPath,
		"-port", "{{.Port}}",
	}
	options = append([]Option{Timeout(90), Browser("android")}, options...)
	return NewWebDriver("http://{{.Address}}/wd/hub", command, options...)
}

func Selendroid ( jarFile string , options ... Option ) * WebDriver { absJARPath , err := filepath . Abs ( jarFile ) if err != nil { return nil } command := [ ] string { " " , " " , absJARPath , " " , " " , } options = append ( [ ] Option { Timeout ( 90 ) , Browser ( " " ) } , options ... ) return NewWebDriver ( " " , command , options ... ) }

// Selendroid returns an instance of a Selendroid WebDriver.
//
// Provided Options will apply as default arguments for new pages.
// New pages will accept invalid SSL certificates by default. This
// may be disabled using the RejectInvalidSSL Option.
//
// The jarFile is a relative or absolute path to Selendroid JAR file.
// Selendroid will return nil if an invalid path is provided.

Selendroid returns an instance of a Selendroid WebDriver . Provided Options will apply as default arguments for new pages . New pages will accept invalid SSL certificates by default . This may be disabled using the RejectInvalidSSL Option . The jarFile is a relative or absolute path to Selendroid JAR file . Selendroid will return nil if an invalid path is provided .


func (s *Selection) SwitchToFrame() error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.Frame(selectedElement.(*api.Element)); err != nil {
		return fmt.Errorf("failed to switch to frame referred to by %s: %s", s, err)
	}
	return nil
}

func ( s * Selection ) SwitchToFrame ( ) error { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return fmt . Errorf ( " " , s , err ) } if err := s . session . Frame ( selectedElement . ( * api . Element ) ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil }

// SwitchToFrame focuses on the frame specified by the selection. All new and
// existing selections will refer to the new frame. All further Page methods
// will apply to this frame as well.

SwitchToFrame focuses on the frame specified by the selection . All new and existing selections will refer to the new frame . All further Page methods will apply to this frame as well .


func (s *Selection) Count() (int, error) {
	elements, err := s.elements.Get()
	if err != nil {
		return 0, fmt.Errorf("failed to select elements from %s: %s", s, err)
	}

	return len(elements), nil
}

func ( s * Selection ) Count ( ) ( int , error ) { elements , err := s . elements . Get ( ) if err != nil { return 0 , fmt . Errorf ( " " , s , err ) } return len ( elements ) , nil }

// Count returns the number of elements that the selection refers to.

Count returns the number of elements that the selection refers to .


func (s *Selection) EqualsElement(other interface{}) (bool, error) {
	otherSelection, ok := other.(*Selection)
	if !ok {
		multiSelection, ok := other.(*MultiSelection)
		if !ok {
			return false, fmt.Errorf("must be *Selection or *MultiSelection")
		}
		otherSelection = &multiSelection.Selection
	}

	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return false, fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	otherElement, err := otherSelection.elements.GetExactlyOne()
	if err != nil {
		return false, fmt.Errorf("failed to select element from %s: %s", other, err)
	}

	equal, err := selectedElement.IsEqualTo(otherElement.(*api.Element))
	if err != nil {
		return false, fmt.Errorf("failed to compare %s to %s: %s", s, other, err)
	}

	return equal, nil
}

func ( s * Selection ) EqualsElement ( other interface { } ) ( bool , error ) { otherSelection , ok := other . ( * Selection ) if ! ok { multiSelection , ok := other . ( * MultiSelection ) if ! ok { return false , fmt . Errorf ( " " ) } otherSelection = & multiSelection . Selection } selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return false , fmt . Errorf ( " " , s , err ) } otherElement , err := otherSelection . elements . GetExactlyOne ( ) if err != nil { return false , fmt . Errorf ( " " , other , err ) } equal , err := selectedElement . IsEqualTo ( otherElement . ( * api . Element ) ) if err != nil { return false , fmt . Errorf ( " " , s , other , err ) } return equal , nil }

// EqualsElement returns whether or not two selections of exactly
// one element refer to the same element.

EqualsElement returns whether or not two selections of exactly one element refer to the same element .


func (s *Selection) MouseToElement() error {
	selectedElement, err := s.elements.GetExactlyOne()
	if err != nil {
		return fmt.Errorf("failed to select element from %s: %s", s, err)
	}

	if err := s.session.MoveTo(selectedElement.(*api.Element), nil); err != nil {
		return fmt.Errorf("failed to move mouse to element for %s: %s", s, err)
	}

	return nil
}

func ( s * Selection ) MouseToElement ( ) error { selectedElement , err := s . elements . GetExactlyOne ( ) if err != nil { return fmt . Errorf ( " " , s , err ) } if err := s . session . MoveTo ( selectedElement . ( * api . Element ) , nil ) ; err != nil { return fmt . Errorf ( " " , s , err ) } return nil }

// MouseToElement moves the mouse over exactly one element in the selection.

MouseToElement moves the mouse over exactly one element in the selection .


func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("[DEBUG] http reverse proxy received connection from %s on path %s\n", r.RemoteAddr, r.RequestURI)
		next.ServeHTTP(w, r)
	})
}

func loggingMiddleware ( next http . Handler ) http . Handler { return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { log . Printf ( " \n " , r . RemoteAddr , r . RequestURI ) next . ServeHTTP ( w , r ) } ) }

// loggingMiddleware logs requests to the proxy


func chainHandlers(mw ...Middleware) Middleware {
	return func(final http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			last := final
			for i := len(mw) - 1; i >= 0; i-- {
				last = mw[i](last)
			}
			last.ServeHTTP(w, r)
		})
	}
}

func chainHandlers ( mw ... Middleware ) Middleware { return func ( final http . Handler ) http . Handler { return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { last := final for i := len ( mw ) - 1 ; i >= 0 ; i -- { last = mw [ i ] ( last ) } last . ServeHTTP ( w , r ) } ) } }

// chainHandlers takes a set of middleware and joins them together
// into a single Middleware, making it much simpler to compose middleware
// together

chainHandlers takes a set of middleware and joins them together into a single Middleware making it much simpler to compose middleware together


func HTTPReverseProxy(options Options) (int, error) {
	port := options.ProxyPort
	var err error

	proxy := httputil.NewSingleHostReverseProxy(&url.URL{
		Scheme: options.TargetScheme,
		Host:   options.TargetAddress,
	})

	if port == 0 {
		port, err = utils.GetFreePort()
		if err != nil {
			log.Println("[ERROR] unable to start reverse proxy server:", err)
			return 0, err
		}
	}

	wrapper := chainHandlers(append(options.Middleware, loggingMiddleware)...)

	log.Println("[DEBUG] starting reverse proxy on port", port)
	go http.ListenAndServe(fmt.Sprintf(":%d", port), wrapper(proxy))

	return port, nil
}

func HTTPReverseProxy ( options Options ) ( int , error ) { port := options . ProxyPort var err error proxy := httputil . NewSingleHostReverseProxy ( & url . URL { Scheme : options . TargetScheme , Host : options . TargetAddress , } ) if port == 0 { port , err = utils . GetFreePort ( ) if err != nil { log . Println ( " " , err ) return 0 , err } } wrapper := chainHandlers ( append ( options . Middleware , loggingMiddleware ) ... ) log . Println ( " " , port ) go http . ListenAndServe ( fmt . Sprintf ( " " , port ) , wrapper ( proxy ) ) return port , nil }

// HTTPReverseProxy provides a default setup for proxying
// internal components within the framework

HTTPReverseProxy provides a default setup for proxying internal components within the framework


func (i *Installer) CheckInstallation() error {

	for binary, versionRange := range versionMap {
		log.Println("[INFO] checking", binary, "within range", versionRange)

		version, err := i.GetVersionForBinary(binary)
		if err != nil {
			return err
		}

		if err = i.CheckVersion(binary, version); err != nil {
			return err
		}
	}

	return nil
}

func ( i * Installer ) CheckInstallation ( ) error { for binary , versionRange := range versionMap { log . Println ( " " , binary , " " , versionRange ) version , err := i . GetVersionForBinary ( binary ) if err != nil { return err } if err = i . CheckVersion ( binary , version ) ; err != nil { return err } } return nil }

// CheckInstallation checks installation of all of the tools


func (i *Installer) CheckVersion(binary, version string) error {
	log.Println("[DEBUG] checking version for binary", binary, "version", version)
	v, err := goversion.NewVersion(version)
	if err != nil {
		log.Println("[DEBUG] err", err)
		return err
	}

	versionRange, ok := versionMap[binary]
	if !ok {
		return fmt.Errorf("unable to find version range for binary %s", binary)
	}

	log.Println("[DEBUG] checking if version", v, "within semver range", versionRange)
	constraints, err := goversion.NewConstraint(versionRange)
	if constraints.Check(v) {
		log.Println("[DEBUG]", v, "satisfies constraints", v, constraints)
		return nil
	}

	return fmt.Errorf("version %s of %s does not match constraint %s", version, binary, versionRange)
}

func ( i * Installer ) CheckVersion ( binary , version string ) error { log . Println ( " " , binary , " " , version ) v , err := goversion . NewVersion ( version ) if err != nil { log . Println ( " " , err ) return err } versionRange , ok := versionMap [ binary ] if ! ok { return fmt . Errorf ( " " , binary ) } log . Println ( " " , v , " " , versionRange ) constraints , err := goversion . NewConstraint ( versionRange ) if constraints . Check ( v ) { log . Println ( " " , v , " " , v , constraints ) return nil } return fmt . Errorf ( " " , version , binary , versionRange ) }

// CheckVersion checks installation of a given binary using semver-compatible
// comparisions

CheckVersion checks installation of a given binary using semver - compatible comparisions


func (i *Installer) GetVersionForBinary(binary string) (version string, err error) {
	log.Println("[DEBUG] running binary", binary)

	content, err := i.commander.Output(binary, "version")
	elements := strings.Split(strings.TrimSpace(string(content)), "\n")
	version = strings.TrimSpace(elements[len(elements)-1])

	return version, err
}

func ( i * Installer ) GetVersionForBinary ( binary string ) ( version string , err error ) { log . Println ( " " , binary ) content , err := i . commander . Output ( binary , " " ) elements := strings . Split ( strings . TrimSpace ( string ( content ) ) , " \n " ) version = strings . TrimSpace ( elements [ len ( elements ) - 1 ] ) return version , err }

// GetVersionForBinary gets the version of a given Ruby binary


func (c *Client) getUser(id string) (*ex.User, error) {

	u := fmt.Sprintf("%s/users/%s", c.Host, id)
	req, err := http.NewRequest("GET", u, nil)

	// NOTE: by default, request bodies are expected to be sent with a Content-Type
	// of application/json. If you don't explicitly set the content-type, you
	// will get a mismatch during Verification.
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", c.token)

	res, err := http.DefaultClient.Do(req)

	if res.StatusCode != 200 || err != nil {
		return nil, fmt.Errorf("get user failed")
	}

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var response ex.User
	err = json.Unmarshal(data, &response)
	if err != nil {
		return nil, err
	}

	return &response, err
}


func (c *Client) login(username string, password string) (*ex.User, error) {
	loginRequest := fmt.Sprintf(`
    {
      "username":"%s",
      "password": "%s"
    }`, username, password)

	res, err := http.Post(fmt.Sprintf("%s/login/10?foo=anything", c.Host), "application/json; charset=utf-8", bytes.NewReader([]byte(loginRequest)))
	if res.StatusCode != 200 || err != nil {
		return nil, fmt.Errorf("login failed")
	}

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var response loginResponse
	err = json.Unmarshal(data, &response)
	if err != nil {
		return nil, err
	}

	return &response.User, err
}

// Login handles the login API call to the User Service.

Login handles the login API call to the User Service .


func (c *Client) loginHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	password := r.FormValue("password")

	user, err := c.login(username, password)
	if err == nil && user != nil {
		c.user = user
		c.err = nil
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}
	c.err = fmt.Errorf("Invalid username/password")
	http.Redirect(w, r, "/", http.StatusFound)
	return
}

func ( c * Client ) loginHandler ( w http . ResponseWriter , r * http . Request ) { username := r . FormValue ( " " ) password := r . FormValue ( " " ) user , err := c . login ( username , password ) if err == nil && user != nil { c . user = user c . err = nil http . Redirect ( w , r , " " , http . StatusFound ) return } c . err = fmt . Errorf ( " " ) http . Redirect ( w , r , " " , http . StatusFound ) return }


func (c *Client) logoutHandler(w http.ResponseWriter, r *http.Request) {
	c.user = nil
	c.err = nil
	http.Redirect(w, r, "/", http.StatusFound)
	return
}

func ( c * Client ) logoutHandler ( w http . ResponseWriter , r * http . Request ) { c . user = nil c . err = nil http . Redirect ( w , r , " " , http . StatusFound ) return }


func (c *Client) viewHandler(w http.ResponseWriter, r *http.Request) {
	data := templateData{
		User:  c.user,
		Error: c.err,
	}
	renderTemplate(w, "login", data)
}

func ( c * Client ) viewHandler ( w http . ResponseWriter , r * http . Request ) { data := templateData { User : c . user , Error : c . err , } renderTemplate ( w , " " , data ) }

// Show the current user if logged in, otherwise display a login form.

Show the current user if logged in otherwise display a login form .


func (c *Client) Run() {
	http.HandleFunc("/login", c.loginHandler)
	http.HandleFunc("/logout", c.logoutHandler)
	http.HandleFunc("/", c.viewHandler)
	fmt.Println("User svc client running on port 8081")
	http.ListenAndServe(":8081", nil)
}

func ( c * Client ) Run ( ) { http . HandleFunc ( " " , c . loginHandler ) http . HandleFunc ( " " , c . logoutHandler ) http . HandleFunc ( " " , c . viewHandler ) fmt . Println ( " " ) http . ListenAndServe ( " " , nil ) }


func (i *Interaction) WithRequest(request Request) *Interaction {
	i.Request = request

	// Check if someone tried to add an object as a string representation
	// as per original allowed implementation, e.g.
	// { "foo": "bar", "baz": like("bat") }
	if isJSONFormattedObject(request.Body) {
		log.Println("[WARN] request body appears to be a JSON formatted object, " +
			"no structural matching will occur. Support for structured strings has been" +
			"deprecated as of 0.13.0")
	}

	return i
}

// WithRequest specifies the details of the HTTP request that will be used to
// confirm that the Provider provides an API listening on the given interface.
// Mandatory.

WithRequest specifies the details of the HTTP request that will be used to confirm that the Provider provides an API listening on the given interface . Mandatory .


func (i *Interaction) WillRespondWith(response Response) *Interaction {
	i.Response = response

	return i
}

func ( i * Interaction ) WillRespondWith ( response Response ) * Interaction { i . Response = response return i }

// WillRespondWith specifies the details of the HTTP response that will be used to
// confirm that the Provider must satisfy. Mandatory.

WillRespondWith specifies the details of the HTTP response that will be used to confirm that the Provider must satisfy . Mandatory .


func isJSONFormattedObject(stringOrObject interface{}) bool {
	switch content := stringOrObject.(type) {
	case []byte:
	case string:
		var obj interface{}
		err := json.Unmarshal([]byte(content), &obj)

		if err != nil {
			return false
		}

		// Check if a map type
		if _, ok := obj.(map[string]interface{}); ok {
			return true
		}
	}

	return false
}

func
isJSONFormattedObject
(
stringOrObject
interface
{
}
)
bool
{
switch
content
:=
stringOrObject
.
(
type
)
{
case
[
]
byte
:
case
string
:
var
obj
interface
{
}
err
:=
json
.
Unmarshal
(
[
]
byte
(
content
)
,
&
obj
)
if
err
!=
{
return
false
}
// Check if a map type
if
_
,
ok
:=
obj
.
(
map
[
string
]
interface
{
}
)
;
ok
{
return
true
}
}
return
false
}

// Checks to see if someone has tried to submit a JSON string
// for an object, which is no longer supported

Checks to see if someone has tried to submit a JSON string for an object which is no longer supported


func (u *UserRepository) ByUsername(username string) (*User, error) {
	if user, ok := u.Users[username]; ok {
		return user, nil
	}
	return nil, ErrNotFound
}

func ( u * UserRepository ) ByUsername ( username string ) ( * User , error ) { if user , ok := u . Users [ username ] ; ok { return user , nil } return nil , ErrNotFound }

// ByUsername finds a user by their username.

ByUsername finds a user by their username .


func (u *UserRepository) ByID(ID int) (*User, error) {
	for _, user := range u.Users {
		if user.ID == ID {
			return user, nil
		}
	}
	return nil, ErrNotFound
}

func ( u * UserRepository ) ByID ( ID int ) ( * User , error ) { for _ , user := range u . Users { if user . ID == ID { return user , nil } } return nil , ErrNotFound }


func UserLogin(w http.ResponseWriter, r *http.Request) {
	var login types.LoginRequest
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("X-Api-Correlation-Id", "1234")

	body, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()

	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	err = json.Unmarshal(body, &login)
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	user, err := userRepository.ByUsername(login.Username)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
	} else if user.Username != login.Username || user.Password != login.Password {
		w.WriteHeader(http.StatusUnauthorized)
	} else {
		w.Header().Set("X-Auth-Token", getAuthToken())
		w.WriteHeader(http.StatusOK)
		res := types.LoginResponse{User: user}
		resBody, _ := json.Marshal(res)
		w.Write(resBody)
	}
}

func UserLogin ( w http . ResponseWriter , r * http . Request ) { var login types . LoginRequest w . Header ( ) . Set ( " " , " " ) w . Header ( ) . Set ( " " , " " ) body , err := ioutil . ReadAll ( r . Body ) defer r . Body . Close ( ) if err != nil { w . WriteHeader ( http . StatusServiceUnavailable ) return } err = json . Unmarshal ( body , & login ) if err != nil { w . WriteHeader ( http . StatusServiceUnavailable ) return } user , err := userRepository . ByUsername ( login . Username ) if err != nil { w . WriteHeader ( http . StatusNotFound ) } else if user . Username != login . Username || user . Password != login . Password { w . WriteHeader ( http . StatusUnauthorized ) } else { w . Header ( ) . Set ( " " , getAuthToken ( ) ) w . WriteHeader ( http . StatusOK ) res := types . LoginResponse { User : user } resBody , _ := json . Marshal ( res ) w . Write ( resBody ) } }

// UserLogin logs a user in, returning an auth token and the user object

UserLogin logs a user in returning an auth token and the user object


func newClient(MockServiceManager client.Service, verificationServiceManager client.Service, messageServiceManager client.Service, publishServiceManager client.Service) *PactClient {
	MockServiceManager.Setup()
	verificationServiceManager.Setup()
	messageServiceManager.Setup()
	publishServiceManager.Setup()

	return &PactClient{
		pactMockSvcManager:     MockServiceManager,
		verificationSvcManager: verificationServiceManager,
		messageSvcManager:      messageServiceManager,
		publishSvcManager:      publishServiceManager,
		TimeoutDuration:        10 * time.Second,
	}
}

func newClient ( MockServiceManager client . Service , verificationServiceManager client . Service , messageServiceManager client . Service , publishServiceManager client . Service ) * PactClient { MockServiceManager . Setup ( ) verificationServiceManager . Setup ( ) messageServiceManager . Setup ( ) publishServiceManager . Setup ( ) return & PactClient { pactMockSvcManager : MockServiceManager , verificationSvcManager : verificationServiceManager , messageSvcManager : messageServiceManager , publishSvcManager : publishServiceManager , TimeoutDuration : 10 * time . Second , } }

// newClient creates a new Pact client manager with the provided services


func NewClient() *PactClient {
	return newClient(&client.MockService{}, &client.VerificationService{}, &client.MessageService{}, &client.PublishService{})
}

func NewClient ( ) * PactClient { return newClient ( & client . MockService { } , & client . VerificationService { } , & client . MessageService { } , & client . PublishService { } ) }

// NewClient creates a new Pact client manager with defaults


func (p *PactClient) ListServers() []*types.MockServer {
	log.Println("[DEBUG] client: starting a server")

	var servers []*types.MockServer

	for port, s := range p.pactMockSvcManager.List() {
		servers = append(servers, &types.MockServer{
			Pid:  s.Process.Pid,
			Port: port,
		})
	}

	return servers
}

func ( p * PactClient ) ListServers ( ) [ ] * types . MockServer { log . Println ( " " ) var servers [ ] * types . MockServer for port , s := range p . pactMockSvcManager . List ( ) { servers = append ( servers , & types . MockServer { Pid : s . Process . Pid , Port : port , } ) } return servers }

// ListServers lists all known Mock Servers


func (p *PactClient) UpdateMessagePact(request types.PactMessageRequest) error {
	log.Println("[DEBUG] client: adding pact message...")

	// Convert request into flags, and validate request
	err := request.Validate()
	if err != nil {
		return err
	}

	svc := p.messageSvcManager.NewService(request.Args)
	cmd := svc.Command()

	stdOutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stdErrPipe, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	err = cmd.Start()
	if err != nil {
		return err
	}
	stdOut, err := ioutil.ReadAll(stdOutPipe)
	if err != nil {
		return err
	}
	stdErr, err := ioutil.ReadAll(stdErrPipe)
	if err != nil {
		return err
	}

	err = cmd.Wait()

	if err == nil {
		return nil
	}

	return fmt.Errorf("error creating message: %s\n\nSTDERR:\n%s\n\nSTDOUT:\n%s", err, stdErr, stdOut)
}

// UpdateMessagePact adds a pact message to a contract file


func (p *PactClient) PublishPacts(request types.PublishRequest) error {
	svc := p.publishSvcManager.NewService(request.Args)
	log.Println("[DEBUG] about to publish pacts")
	cmd := svc.Start()

	log.Println("[DEBUG] waiting for response")
	err := cmd.Wait()

	log.Println("[DEBUG] response from publish", err)

	return err
}

func ( p * PactClient ) PublishPacts ( request types . PublishRequest ) error { svc := p . publishSvcManager . NewService ( request . Args ) log . Println ( " " ) cmd := svc . Start ( ) log . Println ( " " ) err := cmd . Wait ( ) log . Println ( " " , err ) return err }

// PublishPacts publishes a set of pacts to a pact broker


func getPort(rawURL string) int {
	parsedURL, err := url.Parse(rawURL)
	if err == nil {
		splitHost := strings.Split(parsedURL.Host, ":")
		if len(splitHost) == 2 {
			port, err := strconv.Atoi(splitHost[1])
			if err == nil {
				return port
			}
		}
		if parsedURL.Scheme == "https" {
			return 443
		}
		return 80
	}

	return -1
}

func getPort ( rawURL string ) int { parsedURL , err := url . Parse ( rawURL ) if err == nil { splitHost := strings . Split ( parsedURL . Host , " " ) if len ( splitHost ) == 2 { port , err := strconv . Atoi ( splitHost [ 1 ] ) if err == nil { return port } } if parsedURL . Scheme == " " { return 443 } return 80 } return - 1 }


func getAddress(rawURL string) string {
	parsedURL, err := url.Parse(rawURL)
	if err != nil {
		return ""
	}

	splitHost := strings.Split(parsedURL.Host, ":")
	return splitHost[0]
}

func getAddress ( rawURL string ) string { parsedURL , err := url . Parse ( rawURL ) if err != nil { return " " } splitHost := strings . Split ( parsedURL . Host , " " ) return splitHost [ 0 ] }


func sanitiseRubyResponse(response string) string {
	log.Println("[TRACE] response from Ruby process pre-sanitisation:", response)

	r := regexp.MustCompile("(?m)^\\s*#.*$")
	s := r.ReplaceAllString(response, "")

	r = regexp.MustCompile("(?m).*bundle exec rake pact:verify.*$")
	s = r.ReplaceAllString(s, "")

	r = regexp.MustCompile("\\n+")
	s = r.ReplaceAllString(s, "\n")

	return s
}

func sanitiseRubyResponse ( response string ) string { log . Println ( " " , response ) r := regexp . MustCompile ( " \\ " ) s := r . ReplaceAllString ( response , " " ) r = regexp . MustCompile ( " " ) s = r . ReplaceAllString ( s , " " ) r = regexp . MustCompile ( " \\ " ) s = r . ReplaceAllString ( s , " \n " ) return s }

// sanitiseRubyResponse removes Ruby-isms from the response content
// making the output much more human readable

sanitiseRubyResponse removes Ruby - isms from the response content making the output much more human readable


func (p *Publisher) Publish(request types.PublishRequest) error {
	log.Println("[DEBUG] pact publisher: publish pact")

	if p.pactClient == nil {
		c := NewClient()
		p.pactClient = c
	}

	err := request.Validate()

	if err != nil {
		return err
	}

	return p.pactClient.PublishPacts(request)
}

func ( p * Publisher ) Publish ( request types . PublishRequest ) error { log . Println ( " " ) if p . pactClient == nil { c := NewClient ( ) p . pactClient = c } err := request . Validate ( ) if err != nil { return err } return p . pactClient . PublishPacts ( request ) }

// Publish sends the Pacts to a broker, optionally tagging them

Publish sends the Pacts to a broker optionally tagging them


func FindPortInRange(s string) (int, error) {
	// Take care of csv and single value
	if !strings.Contains(s, "-") {
		ports := strings.Split(strings.TrimSpace(s), ",")
		for _, p := range ports {
			i, err := strconv.Atoi(p)
			if err != nil {
				return 0, err
			}
			err = checkPort(i)
			if err != nil {
				continue
			}
			return i, nil
		}
		return 0, errors.New("all passed ports are unusable")
	}
	// Now take care of ranges
	ports := strings.Split(strings.TrimSpace(s), "-")
	if len(ports) != 2 {
		return 0, errors.New("invalid range passed")
	}
	lower, err := strconv.Atoi(ports[0])
	if err != nil {
		return 0, err
	}
	upper, err := strconv.Atoi(ports[1])
	if err != nil {
		return 0, err
	}
	if upper < lower {
		return 0, errors.New("invalid range passed")
	}
	for i := lower; i <= upper; i++ {
		err = checkPort(i)
		if err != nil {
			continue
		}
		return i, nil
	}
	return 0, errors.New("all passed ports are unusable")
}

func
FindPortInRange
(
s
string
)
(
int
,
error
)
{
// Take care of csv and single value
if
!
strings
.
Contains
(
s
,
"
"
)
{
ports
:=
strings
.
Split
(
strings
.
TrimSpace
(
s
)
,
"
"
)
for
_
,
p
:=
range
ports
{
i
,
err
:=
strconv
.
Atoi
(
p
)
if
err
!=
{
return
0
,
err
}
err
=
checkPort
(
i
)
if
err
!=
{
continue
}
return
i
,
}
return
0
,
errors
.
New
(
"
"
)
}
// Now take care of ranges
ports
:=
strings
.
Split
(
strings
.
TrimSpace
(
s
)
,
"
"
)
if
len
(
ports
)
!=
2
{
return
0
,
errors
.
New
(
"
"
)
}
lower
,
err
:=
strconv
.
Atoi
(
ports
[
0
]
)
if
err
!=
{
return
0
,
err
}
upper
,
err
:=
strconv
.
Atoi
(
ports
[
1
]
)
if
err
!=
{
return
0
,
err
}
if
upper
<
lower
{
return
0
,
errors
.
New
(
"
"
)
}
for
i
:=
lower
;
i
<=
upper
;
i
++
{
err
=
checkPort
(
i
)
if
err
!=
{
continue
}
return
i
,
}
return
0
,
errors
.
New
(
"
"
)
}

// FindPortInRange Iterate through CSV or Range of ports to find open port
// Valid inputs are "8081", "8081,8085", "8081-8085". Do not combine
// list and range

FindPortInRange Iterate through CSV or Range of ports to find open port Valid inputs are 8081 8081 8085 8081 - 8085 . Do not combine list and range


func EachLike(content interface{}, minRequired int) Matcher {
	return eachLike{
		Contents: content,
		Min:      minRequired,
	}
}

func EachLike ( content interface { } , minRequired int ) Matcher { return eachLike { Contents : content , Min : minRequired , } }

// EachLike specifies that a given element in a JSON body can be repeated
// "minRequired" times. Number needs to be 1 or greater

EachLike specifies that a given element in a JSON body can be repeated minRequired times . Number needs to be 1 or greater


func Term(generate string, matcher string) Matcher {
	return term{
		Data: termData{
			Generate: generate,
			Matcher: termMatcher{
				Type:  "Regexp",
				O:     0,
				Regex: matcher,
			},
		},
	}
}

func Term ( generate string , matcher string ) Matcher { return term { Data : termData { Generate : generate , Matcher : termMatcher { Type : " " , O : 0 , Regex : matcher , } , } , } }

// Term specifies that the matching should generate a value
// and also match using a regular expression.

Term specifies that the matching should generate a value and also match using a regular expression .


func (m *MapMatcher) UnmarshalJSON(bytes []byte) (err error) {
	sk := make(map[string]string)
	err = json.Unmarshal(bytes, &sk)
	if err != nil {
		return
	}

	*m = make(map[string]Matcher)
	for k, v := range sk {
		(*m)[k] = String(v)
	}

	return
}

func ( m * MapMatcher ) UnmarshalJSON ( bytes [ ] byte ) ( err error ) { sk := make ( map [ string ] string ) err = json . Unmarshal ( bytes , & sk ) if err != nil { return } * m = make ( map [ string ] Matcher ) for k , v := range sk { ( * m ) [ k ] = String ( v ) } return }

// UnmarshalJSON is a custom JSON parser for MapMatcher
// It treats the matchers as strings

UnmarshalJSON is a custom JSON parser for MapMatcher It treats the matchers as strings


func objectToString(obj interface{}) string {
	switch content := obj.(type) {
	case string:
		return content
	default:
		jsonString, err := json.Marshal(obj)
		if err != nil {
			log.Println("[DEBUG] objectToString: error unmarshaling object into string:", err.Error())
			return ""
		}
		return string(jsonString)
	}
}

func objectToString ( obj interface { } ) string { switch content := obj . ( type ) { case string : return content default : jsonString , err := json . Marshal ( obj ) if err != nil { log . Println ( " " , err . Error ( ) ) return " " } return string ( jsonString ) } }

// Takes an object and converts it to a JSON representation


func match(srcType reflect.Type, params params) Matcher {
	switch kind := srcType.Kind(); kind {
	case reflect.Ptr:
		return match(srcType.Elem(), params)
	case reflect.Slice, reflect.Array:
		return EachLike(match(srcType.Elem(), getDefaults()), params.slice.min)
	case reflect.Struct:
		result := StructMatcher{}

		for i := 0; i < srcType.NumField(); i++ {
			field := srcType.Field(i)
			result[field.Tag.Get("json")] = match(field.Type, pluckParams(field.Type, field.Tag.Get("pact")))
		}
		return result
	case reflect.String:
		if params.str.regEx != "" {
			return Term(params.str.example, params.str.regEx)
		}
		if params.str.example != "" {
			return Like(params.str.example)
		}

		return Like("string")
	case reflect.Bool:
		return Like(true)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return Like(1)
	case reflect.Float32, reflect.Float64:
		return Like(1.1)
	default:
		panic(fmt.Sprintf("match: unhandled type: %v", srcType))
	}
}

func match ( srcType reflect . Type , params params ) Matcher { switch kind := srcType . Kind ( ) ; kind { case reflect . Ptr : return match ( srcType . Elem ( ) , params ) case reflect . Slice , reflect . Array : return EachLike ( match ( srcType . Elem ( ) , getDefaults ( ) ) , params . slice . min ) case reflect . Struct : result := StructMatcher { } for i := 0 ; i < srcType . NumField ( ) ; i ++ { field := srcType . Field ( i ) result [ field . Tag . Get ( " " ) ] = match ( field . Type , pluckParams ( field . Type , field . Tag . Get ( " " ) ) ) } return result case reflect . String : if params . str . regEx != " " { return Term ( params . str . example , params . str . regEx ) } if params . str . example != " " { return Like ( params . str . example ) } return Like ( " " ) case reflect . Bool : return Like ( true ) case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 , reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 : return Like ( 1 ) case reflect . Float32 , reflect . Float64 : return Like ( 1.1 ) default : panic ( fmt . Sprintf ( " " , srcType ) ) } }

// match recursively traverses the provided type and outputs a
// matcher string for it that is compatible with the Pact dsl.

match recursively traverses the provided type and outputs a matcher string for it that is compatible with the Pact dsl .


func (p *Pact) AddMessage() *Message {
	log.Println("[DEBUG] pact add message")

	m := &Message{}
	p.MessageInteractions = append(p.MessageInteractions, m)
	return m
}

func ( p * Pact ) AddMessage ( ) * Message { log . Println ( " " ) m := & Message { } p . MessageInteractions = append ( p . MessageInteractions , m ) return m }

// AddMessage creates a new asynchronous consumer expectation


func (p *Pact) AddInteraction() *Interaction {
	p.Setup(true)
	log.Println("[DEBUG] pact add interaction")
	i := &Interaction{}
	p.Interactions = append(p.Interactions, i)
	return i
}

func ( p * Pact ) AddInteraction ( ) * Interaction { p . Setup ( true ) log . Println ( " " ) i := & Interaction { } p . Interactions = append ( p . Interactions , i ) return i }

// AddInteraction creates a new Pact interaction, initialising all
// required things. Will automatically start a Mock Service if none running.

AddInteraction creates a new Pact interaction initialising all required things . Will automatically start a Mock Service if none running .


func (p *Pact) Teardown() *Pact {
	log.Println("[DEBUG] teardown")
	if p.Server != nil {
		server, err := p.pactClient.StopServer(p.Server)

		if err != nil {
			log.Println("error:", err)
		}
		p.Server = server
	}
	return p
}

func ( p * Pact ) Teardown ( ) * Pact { log . Println ( " " ) if p . Server != nil { server , err := p . pactClient . StopServer ( p . Server ) if err != nil { log . Println ( " " , err ) } p . Server = server } return p }

// Teardown stops the Pact Mock Server. This usually is called on completion
// of each test suite.

Teardown stops the Pact Mock Server . This usually is called on completion of each test suite .


func (p *Pact) Verify(integrationTest func() error) error {
	p.Setup(true)
	log.Println("[DEBUG] pact verify")

	// Check if we are verifying messages or if we actually have interactions
	if len(p.Interactions) == 0 {
		return errors.New("there are no interactions to be verified")
	}

	mockServer := &MockService{
		BaseURL:  fmt.Sprintf("http://%s:%d", p.Host, p.Server.Port),
		Consumer: p.Consumer,
		Provider: p.Provider,
	}

	for _, interaction := range p.Interactions {
		err := mockServer.AddInteraction(interaction)
		if err != nil {
			return err
		}
	}

	// Run the integration test
	err := integrationTest()
	if err != nil {
		return err
	}

	// Run Verification Process
	err = mockServer.Verify()
	if err != nil {
		return err
	}

	// Clear out interations
	p.Interactions = make([]*Interaction, 0)

	return mockServer.DeleteInteractions()
}

// Verify runs the current test case against a Mock Service.
// Will cleanup interactions between tests within a suite.

Verify runs the current test case against a Mock Service . Will cleanup interactions between tests within a suite .


func stateHandlerMiddleware(stateHandlers types.StateHandlers) proxy.Middleware {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path == "/__setup" {
				var s *types.ProviderState
				decoder := json.NewDecoder(r.Body)
				decoder.Decode(&s)

				// Setup any provider state
				for _, state := range s.States {
					sf, stateFound := stateHandlers[state]

					if !stateFound {
						log.Printf("[WARN] state handler not found for state: %v", state)
					} else {
						// Execute state handler
						if err := sf(); err != nil {
							log.Printf("[ERROR] state handler for '%v' errored: %v", state, err)
							w.WriteHeader(http.StatusInternalServerError)
							return
						}
					}
				}

				w.WriteHeader(http.StatusOK)
				return
			}

			log.Println("[DEBUG] skipping state handler for request", r.RequestURI)

			// Pass through to application
			next.ServeHTTP(w, r)
		})
	}
}

func
stateHandlerMiddleware
(
stateHandlers
types
.
StateHandlers
)
proxy
.
Middleware
{
return
func
(
next
http
.
Handler
)
http
.
Handler
{
return
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
r
.
URL
.
Path
==
"
"
{
var
s
*
types
.
ProviderState
decoder
:=
json
.
NewDecoder
(
r
.
Body
)
decoder
.
Decode
(
&
s
)
// Setup any provider state
for
_
,
state
:=
range
s
.
States
{
sf
,
stateFound
:=
stateHandlers
[
state
]
if
!
stateFound
{
log
.
Printf
(
"
"
,
state
)
}
else
{
// Execute state handler
if
err
:=
sf
(
)
;
err
!=
{
log
.
Printf
(
"
"
,
state
,
err
)
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
return
}
}
}
w
.
WriteHeader
(
http
.
StatusOK
)
return
}
log
.
Println
(
"
"
,
r
.
RequestURI
)
// Pass through to application
next
.
ServeHTTP
(
w
,
r
)
}
)
}
}

// stateHandlerMiddleware responds to the various states that are
// given during provider verification
//
// statehandler accepts a state object from the verifier and executes
// any state handlers associated with the provider.
// It will not execute further middleware if it is the designted "state" request

stateHandlerMiddleware responds to the various states that are given during provider verification statehandler accepts a state object from the verifier and executes any state handlers associated with the provider . It will not execute further middleware if it is the designted state request


func (p *Pact) VerifyMessageProviderRaw(request VerifyMessageRequest) (types.ProviderVerifierResponse, error) {
	p.Setup(false)
	response := types.ProviderVerifierResponse{}

	// Starts the message wrapper API with hooks back to the message handlers
	// This maps the 'description' field of a message pact, to a function handler
	// that will implement the message producer. This function must return an object and optionally
	// and error. The object will be marshalled to JSON for comparison.
	mux := http.NewServeMux()

	port, err := utils.GetFreePort()
	if err != nil {
		return response, fmt.Errorf("unable to allocate a port for verification: %v", err)
	}

	// Construct verifier request
	verificationRequest := types.VerifyRequest{
		ProviderBaseURL:            fmt.Sprintf("http://localhost:%d", port),
		PactURLs:                   request.PactURLs,
		BrokerURL:                  request.BrokerURL,
		Tags:                       request.Tags,
		BrokerUsername:             request.BrokerUsername,
		BrokerPassword:             request.BrokerPassword,
		BrokerToken:                request.BrokerToken,
		PublishVerificationResults: request.PublishVerificationResults,
		ProviderVersion:            request.ProviderVersion,
		Provider:                   p.Provider,
	}

	mux.HandleFunc("/", messageVerificationHandler(request.MessageHandlers, request.StateHandlers))

	ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	log.Printf("[DEBUG] API handler starting: port %d (%s)", port, ln.Addr())
	go http.Serve(ln, mux)

	portErr := waitForPort(port, "tcp", "localhost", p.ClientTimeout,
		fmt.Sprintf(`Timed out waiting for pact proxy on port %d - check for errors`, port))

	if portErr != nil {
		log.Fatal("Error:", err)
		return response, portErr
	}

	log.Println("[DEBUG] pact provider verification")
	return p.pactClient.VerifyProvider(verificationRequest)
}

// VerifyMessageProviderRaw runs provider message verification.
//
// A Message Producer is analagous to Consumer in the HTTP Interaction model.
// It is the initiator of an interaction, and expects something on the other end
// of the interaction to respond - just in this case, not immediately.

VerifyMessageProviderRaw runs provider message verification . A Message Producer is analagous to Consumer in the HTTP Interaction model . It is the initiator of an interaction and expects something on the other end of the interaction to respond - just in this case not immediately .


func (p *Pact) VerifyMessageConsumerRaw(message *Message, handler MessageConsumer) error {
	log.Printf("[DEBUG] verify message")
	p.Setup(false)

	// Reify the message back to its "example/generated" form
	reified, err := p.pactClient.ReifyMessage(&types.PactReificationRequest{
		Message: message.Content,
	})

	if err != nil {
		return fmt.Errorf("unable to convert consumer test to a valid JSON representation: %v", err)
	}

	t := reflect.TypeOf(message.Type)
	if t != nil && t.Name() != "interface" {
		log.Println("[DEBUG] narrowing type to", t.Name())
		err = json.Unmarshal(reified.ResponseRaw, &message.Type)

		if err != nil {
			return fmt.Errorf("unable to narrow type to %v: %v", t.Name(), err)
		}
	}

	// Yield message, and send through handler function
	generatedMessage :=
		Message{
			Content:     message.Type,
			States:      message.States,
			Description: message.Description,
			Metadata:    message.Metadata,
		}

	err = handler(generatedMessage)
	if err != nil {
		return err
	}

	// If no errors, update Message Pact
	return p.pactClient.UpdateMessagePact(types.PactMessageRequest{
		Message:  message,
		Consumer: p.Consumer,
		Provider: p.Provider,
		PactDir:  p.PactDir,
	})
}

// VerifyMessageConsumerRaw creates a new Pact _message_ interaction to build a testable
// interaction.
//
//
// A Message Consumer is analagous to a Provider in the HTTP Interaction model.
// It is the receiver of an interaction, and needs to be able to handle whatever
// request was provided.

VerifyMessageConsumerRaw creates a new Pact _message_ interaction to build a testable interaction . A Message Consumer is analagous to a Provider in the HTTP Interaction model . It is the receiver of an interaction and needs to be able to handle whatever request was provided .


func (p *mockClient) VerifyProvider(request types.VerifyRequest) (types.ProviderVerifierResponse, error) {
	return p.VerifyProviderResponse, p.VerifyProviderError
}

func ( p * mockClient ) VerifyProvider ( request types . VerifyRequest ) ( types . ProviderVerifierResponse , error ) { return p . VerifyProviderResponse , p . VerifyProviderError }

// VerifyProvider runs the verification process against a running Provider.

VerifyProvider runs the verification process against a running Provider .


func (m *MockService) NewService(args []string) Service {
	m.Args = []string{
		"service",
	}
	m.Args = append(m.Args, args...)

	m.Cmd = getMockServiceCommandPath()
	return m
}

func ( m * MockService ) NewService ( args [ ] string ) Service { m . Args = [ ] string { " " , } m . Args = append ( m . Args , args ... ) m . Cmd = getMockServiceCommandPath ( ) return m }

// NewService creates a new MockService with default settings.

NewService creates a new MockService with default settings .


func (s *ServiceManager) Setup() {
	log.Println("[DEBUG] setting up a service manager")

	s.commandCreatedChan = make(chan *exec.Cmd)
	s.commandCompleteChan = make(chan *exec.Cmd)
	s.processMap = processMap{processes: make(map[int]*exec.Cmd)}

	// Listen for service create/kill
	go s.addServiceMonitor()
	go s.removeServiceMonitor()
}

func
(
s
*
ServiceManager
)
Setup
(
)
{
log
.
Println
(
"
"
)
s
.
commandCreatedChan
=
make
(
chan
*
exec
.
Cmd
)
s
.
commandCompleteChan
=
make
(
chan
*
exec
.
Cmd
)
s
.
processMap
=
processMap
{
processes
:
make
(
map
[
int
]
*
exec
.
Cmd
)
}
// Listen for service create/kill
go
s
.
addServiceMonitor
(
)
go
s
.
removeServiceMonitor
(
)
}


func (s *ServiceManager) addServiceMonitor() {
	log.Println("[DEBUG] starting service creation monitor")
	for {
		select {
		case p := <-s.commandCreatedChan:
			if p != nil && p.Process != nil {
				s.processMap.Set(p.Process.Pid, p)
			}
		}
	}
}

func ( s * ServiceManager ) addServiceMonitor ( ) { log . Println ( " " ) for { select { case p := <- s . commandCreatedChan : if p != nil && p . Process != nil { s . processMap . Set ( p . Process . Pid , p ) } } } }

// addServiceMonitor watches a channel to add services into operation.

addServiceMonitor watches a channel to add services into operation .


func (s *ServiceManager) removeServiceMonitor() {
	log.Println("[DEBUG] starting service removal monitor")
	var p *exec.Cmd
	for {
		select {
		case p = <-s.commandCompleteChan:
			if p != nil && p.Process != nil {
				p.Process.Signal(os.Interrupt)
				s.processMap.Delete(p.Process.Pid)
			}
		}
	}
}

func ( s * ServiceManager ) removeServiceMonitor ( ) { log . Println ( " " ) var p * exec . Cmd for { select { case p = <- s . commandCompleteChan : if p != nil && p . Process != nil { p . Process . Signal ( os . Interrupt ) s . processMap . Delete ( p . Process . Pid ) } } } }

// removeServiceMonitor watches a channel to remove services from operation.

removeServiceMonitor watches a channel to remove services from operation .


func (s *ServiceManager) List() map[int]*exec.Cmd {
	log.Println("[DEBUG] listing services")
	return s.processMap.processes
}

func ( s * ServiceManager ) List ( ) map [ int ] * exec . Cmd { log . Println ( " " ) return s . processMap . processes }


func (s *ServiceManager) Command() *exec.Cmd {
	cmd := exec.Command(s.Cmd, s.Args...)
	env := os.Environ()
	env = append(env, s.Env...)
	cmd.Env = env

	return cmd
}

func ( s * ServiceManager ) Command ( ) * exec . Cmd { cmd := exec . Command ( s . Cmd , s . Args ... ) env := os . Environ ( ) env = append ( env , s . Env ... ) cmd . Env = env return cmd }

// Command creates an os command to be run


func (m *MockService) call(method string, url string, content interface{}) error {
	body, err := json.Marshal(content)
	if err != nil {
		fmt.Println(err)
		return err
	}

	client := &http.Client{}
	var req *http.Request
	if method == "POST" {
		req, err = http.NewRequest(method, url, bytes.NewReader(body))
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		return err
	}

	req.Header.Set("X-Pact-Mock-Service", "true")
	req.Header.Set("Content-Type", "application/json")

	res, err := client.Do(req)
	if err != nil {
		return err
	}

	responseBody, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if res.StatusCode < 200 || res.StatusCode >= 300 {
		return errors.New(string(responseBody))
	}
	return err
}

func ( m * MockService ) call ( method string , url string , content interface { } ) error { body , err := json . Marshal ( content ) if err != nil { fmt . Println ( err ) return err } client := & http . Client { } var req * http . Request if method == " " { req , err = http . NewRequest ( method , url , bytes . NewReader ( body ) ) } else { req , err = http . NewRequest ( method , url , nil ) } if err != nil { return err } req . Header . Set ( " " , " " ) req . Header . Set ( " " , " " ) res , err := client . Do ( req ) if err != nil { return err } responseBody , err := ioutil . ReadAll ( res . Body ) res . Body . Close ( ) if res . StatusCode < 200 || res . StatusCode >= 300 { return errors . New ( string ( responseBody ) ) } return err }

// call sends a message to the Pact service


func (m *MockService) DeleteInteractions() error {
	log.Println("[DEBUG] mock service delete interactions")
	url := fmt.Sprintf("%s/interactions", m.BaseURL)
	return m.call("DELETE", url, nil)
}

func ( m * MockService ) DeleteInteractions ( ) error { log . Println ( " " ) url := fmt . Sprintf ( " " , m . BaseURL ) return m . call ( " " , url , nil ) }

// DeleteInteractions removes any previous Mock Service Interactions.

DeleteInteractions removes any previous Mock Service Interactions .


func (m *MockService) AddInteraction(interaction *Interaction) error {
	log.Println("[DEBUG] mock service add interaction")
	url := fmt.Sprintf("%s/interactions", m.BaseURL)
	return m.call("POST", url, interaction)
}

func ( m * MockService ) AddInteraction ( interaction * Interaction ) error { log . Println ( " " ) url := fmt . Sprintf ( " " , m . BaseURL ) return m . call ( " " , url , interaction ) }

// AddInteraction adds a new Pact Mock Service interaction.

AddInteraction adds a new Pact Mock Service interaction .


func (m *MockService) WritePact() error {
	log.Println("[DEBUG] mock service write pact")

	if m.Consumer == "" || m.Provider == "" {
		return errors.New("Consumer and Provider name need to be provided")
	}
	if m.PactFileWriteMode == "" {
		m.PactFileWriteMode = "overwrite"
	}

	pact := map[string]interface{}{
		"consumer": map[string]string{
			"name": m.Consumer,
		},
		"provider": map[string]string{
			"name": m.Provider,
		},
		"pactFileWriteMode": m.PactFileWriteMode,
	}

	url := fmt.Sprintf("%s/pact", m.BaseURL)
	return m.call("POST", url, pact)
}

func ( m * MockService ) WritePact ( ) error { log . Println ( " " ) if m . Consumer == " " || m . Provider == " " { return errors . New ( " " ) } if m . PactFileWriteMode == " " { m . PactFileWriteMode = " " } pact := map [ string ] interface { } { " " : map [ string ] string { " " : m . Consumer , } , " " : map [ string ] string { " " : m . Provider , } , " " : m . PactFileWriteMode , } url := fmt . Sprintf ( " " , m . BaseURL ) return m . call ( " " , url , pact ) }

// WritePact writes the pact file to disk.

WritePact writes the pact file to disk .