github.com/mattdotmatt/gauge@v0.3.2-0.20160421115137-425a4cdccb62/parser/processor.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 parser
    19  
    20  import (
    21  	"bytes"
    22  	"fmt"
    23  	"strings"
    24  
    25  	"github.com/getgauge/gauge/gauge"
    26  )
    27  
    28  func processSpec(parser *SpecParser, token *Token) (*ParseError, bool) {
    29  	if len(strings.TrimSpace(token.Value)) < 1 {
    30  		return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Spec heading should have at least one character"}, true
    31  	}
    32  	return nil, false
    33  }
    34  
    35  func processTearDown(parser *SpecParser, token *Token) (*ParseError, bool) {
    36  	if len(token.Value) < 3 {
    37  		return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Teardown should have at least three underscore characters"}, true
    38  	}
    39  	return nil, false
    40  }
    41  
    42  func processDataTable(parser *SpecParser, token *Token) (*ParseError, bool) {
    43  	if len(strings.TrimSpace(strings.Replace(token.Value, "table:", "", 1))) == 0 {
    44  		return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Table location not specified"}, true
    45  	}
    46  	resolvedArg, err := newSpecialTypeResolver().resolve(token.Value)
    47  	if resolvedArg == nil || err != nil {
    48  		return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: fmt.Sprintf("Could not resolve table from %s", token.LineText)}, true
    49  	}
    50  	return nil, false
    51  }
    52  
    53  func processScenario(parser *SpecParser, token *Token) (*ParseError, bool) {
    54  	if len(strings.TrimSpace(token.Value)) < 1 {
    55  		return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Scenario heading should have at least one character"}, true
    56  	}
    57  	parser.clearState()
    58  	return nil, false
    59  }
    60  
    61  func processComment(parser *SpecParser, token *Token) (*ParseError, bool) {
    62  	parser.clearState()
    63  	addStates(&parser.currentState, commentScope)
    64  	return nil, false
    65  }
    66  
    67  func processTag(parser *SpecParser, token *Token) (*ParseError, bool) {
    68  	parser.clearState()
    69  	tokens := splitAndTrimTags(token.Value)
    70  
    71  	for _, tagValue := range tokens {
    72  		if len(tagValue) > 0 {
    73  			token.Args = append(token.Args, tagValue)
    74  		}
    75  	}
    76  	return nil, false
    77  }
    78  
    79  func processTable(parser *SpecParser, token *Token) (*ParseError, bool) {
    80  	var buffer bytes.Buffer
    81  	shouldEscape := false
    82  	for i, element := range token.Value {
    83  		if i == 0 {
    84  			continue
    85  		}
    86  		if shouldEscape {
    87  			buffer.WriteRune(element)
    88  			shouldEscape = false
    89  			continue
    90  		}
    91  		if element == '\\' {
    92  			shouldEscape = true
    93  			continue
    94  		} else if element == '|' {
    95  			trimmedValue := strings.TrimSpace(buffer.String())
    96  
    97  			if token.Kind == gauge.TableHeader {
    98  				if len(trimmedValue) == 0 {
    99  					return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Table header should not be blank"}, true
   100  				}
   101  
   102  				if arrayContains(token.Args, trimmedValue) {
   103  					return &ParseError{LineNo: parser.lineNo, LineText: token.Value, Message: "Table header cannot have repeated column values"}, true
   104  				}
   105  			}
   106  			token.Args = append(token.Args, trimmedValue)
   107  			buffer.Reset()
   108  		} else {
   109  			buffer.WriteRune(element)
   110  		}
   111  
   112  	}
   113  
   114  	if !isInState(parser.currentState, tableScope) {
   115  		addStates(&parser.currentState, tableScope)
   116  	} else {
   117  		addStates(&parser.currentState, tableDataScope)
   118  	}
   119  
   120  	return nil, false
   121  }
   122  
   123  func processConceptStep(spec *gauge.Specification, step *gauge.Step, conceptDictionary *gauge.ConceptDictionary) {
   124  	if conceptFromDictionary := conceptDictionary.Search(step.Value); conceptFromDictionary != nil {
   125  		createConceptStep(spec, conceptFromDictionary.ConceptStep, step)
   126  	}
   127  }
   128  
   129  func splitAndTrimTags(tag string) []string {
   130  	listOfTags := strings.Split(tag, ",")
   131  	for i, aTag := range listOfTags {
   132  		listOfTags[i] = strings.TrimSpace(aTag)
   133  	}
   134  	return listOfTags
   135  }