github.com/mattdotmatt/gauge@v0.3.2-0.20160421115137-425a4cdccb62/gauge/step.go (about)

     1  // Copyright 2015 ThoughtWorks, Inc.
     2  
     3  // This file is part of Gauge.
     4  
     5  // Gauge is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  
    10  // Gauge is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  
    15  // You should have received a copy of the GNU General Public License
    16  // along with Gauge.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package gauge
    19  
    20  import (
    21  	"fmt"
    22  	"regexp"
    23  	"strings"
    24  
    25  	"github.com/getgauge/gauge/gauge_messages"
    26  	"github.com/golang/protobuf/proto"
    27  )
    28  
    29  type StepValue struct {
    30  	Args                   []string
    31  	StepValue              string
    32  	ParameterizedStepValue string
    33  }
    34  
    35  type Step struct {
    36  	LineNo         int
    37  	Value          string
    38  	LineText       string
    39  	Args           []*StepArg
    40  	IsConcept      bool
    41  	Lookup         ArgLookup
    42  	ConceptSteps   []*Step
    43  	Fragments      []*gauge_messages.Fragment
    44  	Parent         *Step
    45  	HasInlineTable bool
    46  	Items          []Item
    47  	PreComments    []*Comment
    48  }
    49  
    50  func (step *Step) GetArg(name string) *StepArg {
    51  	arg := step.Lookup.GetArg(name)
    52  	// Return static values
    53  	if arg != nil && arg.ArgType != Dynamic {
    54  		return arg
    55  	}
    56  	if step.Parent == nil {
    57  		return step.Lookup.GetArg(name)
    58  	}
    59  	return step.Parent.GetArg(step.Lookup.GetArg(name).Value)
    60  }
    61  
    62  func (step *Step) getLineText() string {
    63  	if step.HasInlineTable {
    64  		return fmt.Sprintf("%s <%s>", step.LineText, TableArg)
    65  	}
    66  	return step.LineText
    67  }
    68  
    69  func (step *Step) Rename(oldStep Step, newStep Step, isRefactored bool, orderMap map[int]int, isConcept *bool) bool {
    70  	if strings.TrimSpace(step.Value) != strings.TrimSpace(oldStep.Value) {
    71  		return isRefactored
    72  	}
    73  	if step.IsConcept {
    74  		*isConcept = true
    75  	}
    76  	step.Value = newStep.Value
    77  
    78  	step.Args = step.getArgsInOrder(newStep, orderMap)
    79  	return true
    80  }
    81  
    82  func (step *Step) getArgsInOrder(newStep Step, orderMap map[int]int) []*StepArg {
    83  	args := make([]*StepArg, len(newStep.Args))
    84  	for key, value := range orderMap {
    85  		arg := &StepArg{Value: newStep.Args[key].Value, ArgType: Static}
    86  		if step.IsConcept {
    87  			arg = &StepArg{Value: newStep.Args[key].Value, ArgType: Dynamic}
    88  		}
    89  		if value != -1 {
    90  			arg = step.Args[value]
    91  		}
    92  		args[key] = arg
    93  	}
    94  	return args
    95  }
    96  
    97  func (step *Step) deepCopyStepArgs() []*StepArg {
    98  	copiedStepArgs := make([]*StepArg, 0)
    99  	for _, conceptStepArg := range step.Args {
   100  		temp := new(StepArg)
   101  		*temp = *conceptStepArg
   102  		copiedStepArgs = append(copiedStepArgs, temp)
   103  	}
   104  	return copiedStepArgs
   105  }
   106  
   107  func (step *Step) ReplaceArgsWithDynamic(args []*StepArg) {
   108  	for i, arg := range step.Args {
   109  		for _, conceptArg := range args {
   110  			if arg.String() == conceptArg.String() {
   111  				if conceptArg.ArgType == SpecialString || conceptArg.ArgType == SpecialTable {
   112  					reg := regexp.MustCompile(".*:")
   113  					step.Args[i] = &StepArg{Value: reg.ReplaceAllString(conceptArg.Name, ""), ArgType: Dynamic}
   114  					continue
   115  				}
   116  				step.Args[i] = &StepArg{Value: replaceParamChar(conceptArg.Value), ArgType: Dynamic}
   117  			}
   118  		}
   119  	}
   120  }
   121  
   122  func (step *Step) AddArgs(args ...*StepArg) {
   123  	step.Args = append(step.Args, args...)
   124  	step.PopulateFragments()
   125  }
   126  
   127  func (step *Step) AddInlineTableHeaders(headers []string) {
   128  	tableArg := &StepArg{ArgType: TableArg}
   129  	tableArg.Table.AddHeaders(headers)
   130  	step.AddArgs(tableArg)
   131  }
   132  
   133  func (step *Step) AddInlineTableRow(row []TableCell) {
   134  	lastArg := step.Args[len(step.Args)-1]
   135  	lastArg.Table.addRows(row)
   136  	step.PopulateFragments()
   137  }
   138  
   139  func (step *Step) PopulateFragments() {
   140  	r := regexp.MustCompile(ParameterPlaceholder)
   141  	/*
   142  		enter {} and {} bar
   143  		returns
   144  		[[6 8] [13 15]]
   145  	*/
   146  	argSplitIndices := r.FindAllStringSubmatchIndex(step.Value, -1)
   147  	step.Fragments = make([]*gauge_messages.Fragment, 0)
   148  	if len(step.Args) == 0 {
   149  		step.Fragments = append(step.Fragments, &gauge_messages.Fragment{FragmentType: gauge_messages.Fragment_Text.Enum(), Text: proto.String(step.Value)})
   150  		return
   151  	}
   152  
   153  	textStartIndex := 0
   154  	for argIndex, argIndices := range argSplitIndices {
   155  		if textStartIndex < argIndices[0] {
   156  			step.Fragments = append(step.Fragments, &gauge_messages.Fragment{FragmentType: gauge_messages.Fragment_Text.Enum(), Text: proto.String(step.Value[textStartIndex:argIndices[0]])})
   157  		}
   158  		parameter := convertToProtoParameter(step.Args[argIndex])
   159  		step.Fragments = append(step.Fragments, &gauge_messages.Fragment{FragmentType: gauge_messages.Fragment_Parameter.Enum(), Parameter: parameter})
   160  		textStartIndex = argIndices[1]
   161  	}
   162  	if textStartIndex < len(step.Value) {
   163  		step.Fragments = append(step.Fragments, &gauge_messages.Fragment{FragmentType: gauge_messages.Fragment_Text.Enum(), Text: proto.String(step.Value[textStartIndex:len(step.Value)])})
   164  	}
   165  
   166  }
   167  
   168  // Not copying parent as it enters an infinite loop in case of nested concepts. This is because the steps under the concept
   169  // are copied and their parent copying again comes back to copy the same concept.
   170  func (self *Step) GetCopy() *Step {
   171  	if !self.IsConcept {
   172  		return self
   173  	}
   174  	nestedStepsCopy := make([]*Step, 0)
   175  	for _, nestedStep := range self.ConceptSteps {
   176  		nestedStepsCopy = append(nestedStepsCopy, nestedStep.GetCopy())
   177  	}
   178  
   179  	copiedConceptStep := new(Step)
   180  	*copiedConceptStep = *self
   181  	copiedConceptStep.ConceptSteps = nestedStepsCopy
   182  	copiedConceptStep.Lookup = *self.Lookup.GetCopy()
   183  	return copiedConceptStep
   184  }
   185  
   186  func (self *Step) CopyFrom(another *Step) {
   187  	self.IsConcept = another.IsConcept
   188  
   189  	if another.Args == nil {
   190  		self.Args = nil
   191  	} else {
   192  		self.Args = make([]*StepArg, len(another.Args))
   193  		copy(self.Args, another.Args)
   194  	}
   195  
   196  	if another.ConceptSteps == nil {
   197  		self.ConceptSteps = nil
   198  	} else {
   199  		self.ConceptSteps = make([]*Step, len(another.ConceptSteps))
   200  		copy(self.ConceptSteps, another.ConceptSteps)
   201  	}
   202  
   203  	if another.Fragments == nil {
   204  		self.Fragments = nil
   205  	} else {
   206  		self.Fragments = make([]*gauge_messages.Fragment, len(another.Fragments))
   207  		copy(self.Fragments, another.Fragments)
   208  	}
   209  
   210  	self.LineNo = another.LineNo
   211  	self.LineText = another.LineText
   212  	self.HasInlineTable = another.HasInlineTable
   213  	self.Value = another.Value
   214  	self.Lookup = another.Lookup
   215  	self.Parent = another.Parent
   216  }
   217  
   218  func (step Step) Kind() TokenKind {
   219  	return StepKind
   220  }
   221  
   222  func replaceParamChar(text string) string {
   223  	return strings.Replace(strings.Replace(text, "<", "{", -1), ">", "}", -1)
   224  }