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 }