Esempio n. 1
0
        public void IgnoresCommentsAnywhereTheyAreEncountered()
        {
            var result = parser.Parse(@"
# comment outside of anything

Feature: Distribution with energy constraints
    # comment in the story text
	Verifies that the energy constraints are taken into account when distributing.
    # comment in the story text

	Background:
        # comment in background
		Given that the test site exists

	Scenario: Test Scenario
        # comment in scenario
		Given the following analog local units:
			| Alias			| TechMin	| TechMax	| ForecastMin	| ForecastMax	| EstMaxCap	| ObsMin	| ObsMax	| ProdOrConsCost	| Efficiency	|
			| REG_T1_001	| 9 kW		| 12 kW		| 0 kW			| 12 kW			| 2 kWh		| 0 m		| 2 m		| 10				| 1				|
			| REG_T1_002	| 9 kW		| 12 kW		| 0 kW			| 12 kW			| 2 kWh		| 0 m		| 2 m		| 100				| 1				|
        # comment in scenario
        # comment in scenario
        # comment in scenario
		and the following signals:
			| Tag				| Value	|
			| REG_T1_001.CurObs	| 2		|
			| REG_T1_002.CurObs	| 2		|"                        );

            var features = result.Features;

            Assert.AreEqual(1, features.Count);
            var feature = features[0];

            Assert.AreEqual("Distribution with energy constraints", feature.Headline);
            Assert.AreEqual("Verifies that the energy constraints are taken into account when distributing.\r\n", feature.Description);
            var scenarios = feature.Scenarios;

            Assert.AreEqual(1, scenarios.Count);
            var scenario = scenarios[0];

            Assert.AreEqual("Test Scenario", scenario.Headline);
            var steps = scenario.Steps;

            Assert.AreEqual(2, steps.Count);
            Assert.AreEqual(Step.Given("the following analog local units:").ToString(), steps[0].ToString());
            Assert.AreEqual(Step.And("the following signals:", StepType.Given).ToString(), steps[1].ToString());
        }
Esempio n. 2
0
        ///<summary>
        /// Call this function to parse a piece of text, specifying its file origin (which will generate better error messages).
        ///</summary>
        ///<param name="fileName">Name of file origin of the Gherkin-text</param>
        ///<param name="text">Gherkin-text to parse</param>
        ///<returns>A parse result including the AST</returns>
        public ParseResult Parse(string fileName, string text)
        {
            var features = new List <Feature>();

            using (var reader = new StringReader(text))
            {
                var accumulatedTags = new List <string>();

                string line;

                Feature  currentFeature     = null;
                Scenario currentScenario    = null;
                StepType?mostRecentStepType = null;
                var      tableColumnNames   = new List <string>();
                var      parsingExamples    = false;
                var      parsingBackground  = false;

                var lineNumber = 0;

                while ((line = reader.ReadLine()) != null)
                {
                    line = line.Trim();
                    lineNumber++;

                    if (ShouldBeIgnored(line))
                    {
                        continue;
                    }

                    if (line.StartsWith("@"))
                    {
                        var tokens     = line.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        var invalidTag = tokens.FirstOrDefault(t => !t.StartsWith("@"));

                        if (invalidTag != null)
                        {
                            throw new GherkinParseException(fileName, lineNumber, line,
                                                            "'{0}' is not a valid tag - tags must begin with '@', e.g. '@important'",
                                                            invalidTag);
                        }

                        var tags = tokens.Select(t => t.TrimStart('@'));

                        accumulatedTags.AddRange(tags);

                        continue;
                    }

                    if (line.StartsWith(FeatureIntroduction, Comparison))
                    {
                        var featureText = line.Substring(FeatureIntroduction.Length).Trim();
                        currentFeature = new Feature(featureText, accumulatedTags);
                        accumulatedTags.Clear();
                        features.Add(currentFeature);
                        currentScenario    = null;
                        mostRecentStepType = null;
                        continue;
                    }

                    if (currentFeature == null)
                    {
                        currentFeature = Feature.NewAnonymousFeature(accumulatedTags);
                        accumulatedTags.Clear();
                        features.Add(currentFeature);
                    }

                    if (line.StartsWith("Background:", Comparison))
                    {
                        parsingBackground = true;
                        continue;
                    }

                    if (line.StartsWith(ScenarioIntroduction, Comparison))
                    {
                        var scenarioText = line.Substring(line.IndexOf(":") + 1).Trim();
                        currentScenario = new ExecutableScenario(scenarioText, accumulatedTags.Concat(currentFeature.Tags));
                        accumulatedTags.Clear();
                        tableColumnNames.Clear();
                        currentFeature.Scenarios.Add(currentScenario);
                        mostRecentStepType = null;
                        parsingExamples    = parsingBackground = false;
                        continue;
                    }

                    if (line.StartsWith(ScenarioOutlineIntroduction, Comparison))
                    {
                        var scenarioText = line.Substring(line.IndexOf(":") + 1).Trim();
                        currentScenario = new ScenarioOutline(scenarioText, accumulatedTags.Concat(currentFeature.Tags));
                        accumulatedTags.Clear();
                        tableColumnNames.Clear();
                        currentFeature.Scenarios.Add(currentScenario);
                        mostRecentStepType = null;
                        parsingExamples    = parsingBackground = false;
                        continue;
                    }

                    if (line.StartsWith(ExamplesIntroduction, Comparison))
                    {
                        if (!(currentScenario is ScenarioOutline))
                        {
                            throw new GherkinParseException(fileName, lineNumber, line, "Cannot specify examples in an ordinary scenario. Please use the 'Scenario outline:' introduction if you mean to specify examples");
                        }

                        parsingExamples = true;

                        continue;
                    }

                    if (parsingBackground)
                    {
                        if (string.IsNullOrEmpty(line))
                        {
                            continue;
                        }

                        if (line.StartsWith("and", Comparison))
                        {
                            if (mostRecentStepType == null)
                            {
                                throw new GherkinParseException(fileName, lineNumber, line,
                                                                @"Lines can only be introduced with ""and"" when it's preceded by either ""given"", ""when"", or ""then"".");
                            }

                            currentFeature.BackgroundSteps.Add(Step.And(line.Substring("and".Length).Trim(),
                                                                        mostRecentStepType.Value));
                        }
                        else if (line.StartsWith("given", Comparison))
                        {
                            currentFeature.BackgroundSteps.Add(Step.Given(line.Substring("given".Length).Trim()));
                            mostRecentStepType = StepType.Given;
                            tableColumnNames.Clear();
                        }
                        else if (line.StartsWith("|"))
                        {
                            var tokens = line.Split('|').Select(s => s.Trim()).ToArray();

                            if (!tableColumnNames.Any())
                            {
                                tableColumnNames.AddRange(tokens);
                            }
                            else
                            {
                                var dict = new Dictionary <string, string>();

                                for (var index = 0; index < tokens.Length; index++)
                                {
                                    var key = tableColumnNames[index];
                                    if (string.IsNullOrEmpty(key))
                                    {
                                        continue;
                                    }

                                    dict[key] = tokens[index];
                                }

                                currentFeature.BackgroundSteps.Last().Parameters.Add(dict);
                            }
                        }
                        else
                        {
                            throw new GherkinParseException(fileName, lineNumber, line,
                                                            @"Expected line to start with either ""given"", or ""|"". Please note that ""when"" or ""then"" steps may not appear inside the background element.");
                        }

                        continue;
                    }

                    if (currentScenario != null)
                    {
                        if (string.IsNullOrEmpty(line))
                        {
                            continue;
                        }

                        if (line.StartsWith("and", Comparison))
                        {
                            if (mostRecentStepType == null)
                            {
                                throw new GherkinParseException(fileName, lineNumber, line,
                                                                @"Lines can only be introduced with ""and"" when it's preceded by either ""given"", ""when"", ""then"", or ""|"".");
                            }

                            currentScenario.Steps.Add(Step.And(line.Substring("and".Length).Trim(),
                                                               mostRecentStepType.Value));
                            tableColumnNames.Clear();
                        }
                        else if (line.StartsWith("given", Comparison))
                        {
                            currentScenario.Steps.Add(Step.Given(line.Substring("given".Length).Trim()));
                            mostRecentStepType = StepType.Given;
                            tableColumnNames.Clear();
                        }
                        else if (line.StartsWith("when", Comparison))
                        {
                            currentScenario.Steps.Add(Step.When(line.Substring("when".Length).Trim()));
                            mostRecentStepType = StepType.When;
                            tableColumnNames.Clear();
                        }
                        else if (line.StartsWith("then", Comparison))
                        {
                            currentScenario.Steps.Add(Step.Then(line.Substring("then".Length).Trim()));
                            mostRecentStepType = StepType.Then;
                            tableColumnNames.Clear();
                        }
                        else if (line.StartsWith("|"))
                        {
                            var tokens = line.Split('|').Select(s => s.Trim()).ToArray();

                            if (!tableColumnNames.Any())
                            {
                                tableColumnNames.AddRange(tokens);
                            }
                            else
                            {
                                var dict = new Dictionary <string, string>();

                                for (var index = 0; index < tokens.Length; index++)
                                {
                                    var key = tableColumnNames[index];
                                    if (string.IsNullOrEmpty(key))
                                    {
                                        continue;
                                    }

                                    dict[key] = tokens[index];
                                }

                                if (parsingExamples)
                                {
                                    ((ScenarioOutline)currentScenario).Examples.Add(dict);
                                }
                                else
                                {
                                    currentScenario.Steps.Last().Parameters.Add(dict);
                                }
                            }
                        }
                        else
                        {
                            throw new GherkinParseException(fileName, lineNumber, line,
                                                            @"Expected line to start with either ""given"", ""when"", or ""then"".");
                        }

                        continue;
                    }

                    currentFeature.AddText(line);
                    continue;
                }
            }

            features.ForEach(feature => AssertConsistency(feature, fileName));

            return(new ParseResult(features));
        }