Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions PanoramicData.IssueAssessment.Tests/Rubrics/HeadingKeywordTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using PanoramicData.IssueAssessment.Mapping;
using PanoramicData.IssueAssessment.Rubrics;

namespace PanoramicData.IssueAssessment.Tests.Rubrics;

/// <summary>
/// MS-23199 Section headings are credited whatever their level (h1 to h4), case or wording variant.
/// </summary>
public class HeadingKeywordTests : TestBase
{
private static readonly IssueAssessor Assessor = new(BuiltInRubrics.PanoramicDataTicketQuality);

[Theory]
[InlineData("Current Behavior", "Expected Behavior")]
[InlineData("Current Behaviour", "Expected Behaviour")]
[InlineData("Actual Behavior", "Expected Behavior")]
[InlineData("Actual Result", "Expected Result")]
[InlineData("Current Behavior", "Desired Behavior")]
[InlineData("current behavior", "EXPECTED BEHAVIOR")]
public async Task CurrentAndExpectedHeadings_ScoreFull_WhateverTheVariantOrCase(string current, string expected)
{
int score = await RawScore("CurrentVsExpected", $"h2. {current}\r\nRows with line breaks are missing.\r\n\r\nh2. {expected}\r\nEvery row is exported.");

score.Should().Be(100);
}

[Theory]
[InlineData("h1.")]
[InlineData("h2.")]
[InlineData("h3.")]
[InlineData("h4.")]
public async Task CurrentAndExpectedHeadings_ScoreFull_AtEveryJiraHeadingLevel(string marker)
{
int score = await RawScore("CurrentVsExpected", $"{marker} Current Behavior\r\nRows are missing.\r\n\r\n{marker} Expected Behavior\r\nEvery row is exported.");

score.Should().Be(100);
}

[Fact]
public async Task CurrentHeadingAlone_StillScoresHalf()
{
int score = await RawScore("CurrentVsExpected", "h2. Actual Result\r\nRows are missing.");

score.Should().Be(50);
}

[Theory]
[InlineData("Acceptance Criteria")]
[InlineData("Success Criteria")]
[InlineData("Definition of Done")]
[InlineData("ACCEPTANCE CRITERIA")]
public async Task CriteriaHeadings_RaiseTestabilityAboveADescriptionWithNone(string heading)
{
const string Body = "Rows with line breaks are missing from the export.";

int without = await RawScore("Testability", Body);
int with = await RawScore("Testability", $"{Body}\r\n\r\nh2. {heading}\r\n# Every row is exported\r\n# Line breaks are preserved");

with.Should().BeGreaterThan(without);
}

private static async Task<int> RawScore(string name, string description)
{
NormalizedIssue issue = new()
{
Key = "OPS-1",
Project = "OPS",
Title = "Export to CSV drops rows that contain line breaks",
Description = description,
IssueType = "Bug",
Status = "In Progress",
Platform = "Jira",
Labels = [],
};
using JsonDocument document = issue.ToJsonDocument();
AssessmentReport report = AssessmentReport.From(await Assessor.AssessAsync(document, CancellationToken));
return (int)report.Categories.SelectMany(category => category.Assessments).Single(item => item.Name == name).RawScore!.Value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
"measures": {
"scope": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "scope:", "h[1-6]\\.[^\\r\\n]*scope", "\\*\\*[^\\r\\n]*scope", "questions?\\s+to\\s+(answer|investigate)", "investigate\\s+(whether|if|how|why)", "determine\\s+(whether|if|how|why)", "find\\s+out", "understand\\s+(how|why|what)" ] },
"deliverables": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "deliverable", "findings", "recommendation", "report", "document", "conclusion", "outcome", "result\\s+of\\s+(investigation|research|analysis)" ] },
"criteria": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "should\\s+(be|display|show|return|have|not)", "must\\s+(be|display|show|return|have|not)", "verify\\s+that", "acceptance\\s+criteria", "h[23]\\.\\s*acceptance\\s+criteria", "expected\\s+(result|behavior|behaviour|outcome)", "pass\\s+criteria", "success\\s+criteria" ] },
"criteria": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "should\\s+(be|display|show|return|have|not)", "must\\s+(be|display|show|return|have|not)", "verify\\s+that", "acceptance\\s+criteria", "h[1-4]\\.\\s*acceptance\\s+criteria", "expected\\s+(result|behavior|behaviour|outcome)", "pass\\s+criteria", "success\\s+criteria", "definition\\s+of\\s+done" ] },
"criteriaHeadings": { "type": "criteriaHeadingCount", "source": { "paths": [ "$.description" ] } }
},
"tiers": [
Expand Down Expand Up @@ -215,8 +215,8 @@
"type": "tiered",
"measures": {
"context": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "background:", "h[1-6]\\.[^\\r\\n]*background", "context:", "h[1-6]\\.[^\\r\\n]*context", "\\*\\*[^\\r\\n]*(background|context)", "motivation:", "why\\s+it\\s+matters", "why\\s+(we|this)", "reason\\s+for", "because" ] },
"current": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "current(ly)?(\\s+behavior|\\s+behaviour)?:", "h[23]\\.\\s*current(\\s*/\\s*actual)?\\s*(behavior|behaviour)", "\\*\\*current\\s*(behavior|behaviour)\\*\\*", "\\*current(\\s*/\\s*actual)?\\s*(behavior|behaviour)?\\*", "\\*actual\\s*(behavior|behaviour)?\\*", "actual(\\s+behavior|\\s+behaviour)?:", "what\\s+happens:", "observed:", "bug:", "issue:", "problem:" ] },
"expected": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "expected(\\s+behavior|\\s+behaviour)?:", "h[23]\\.\\s*expected\\s*(behavior|behaviour)", "\\*\\*expected\\s*(behavior|behaviour)\\*\\*", "\\*expected\\s*(behavior|behaviour)?\\*", "should\\s+be:", "desired:", "correct\\s+behavior:", "fix:", "solution:", "h2\\.\\s*acceptance\\s+criteria", "h3\\.\\s*acceptance\\s+criteria", "acceptance\\s+criteria:", "\\*\\*acceptance\\s+criteria\\*\\*" ] }
"current": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "current(ly)?(\\s+behavior|\\s+behaviour)?:", "h[1-4]\\.\\s*(current|actual)(\\s*/\\s*(actual|current))?\\s*(behavior|behaviour|result)", "\\*\\*current\\s*(behavior|behaviour)\\*\\*", "\\*current(\\s*/\\s*actual)?\\s*(behavior|behaviour)?\\*", "\\*actual\\s*(behavior|behaviour)?\\*", "actual(\\s+behavior|\\s+behaviour)?:", "what\\s+happens:", "observed:", "bug:", "issue:", "problem:" ] },
"expected": { "type": "patternMatchCount", "source": { "paths": [ "$.title", "$.description" ] }, "patterns": [ "expected(\\s+behavior|\\s+behaviour)?:", "h[1-4]\\.\\s*(expected|desired)\\s*(behavior|behaviour|result|outcome)", "\\*\\*expected\\s*(behavior|behaviour)\\*\\*", "\\*expected\\s*(behavior|behaviour)?\\*", "should\\s+be:", "desired:", "correct\\s+behavior:", "fix:", "solution:", "h2\\.\\s*acceptance\\s+criteria", "h3\\.\\s*acceptance\\s+criteria", "acceptance\\s+criteria:", "\\*\\*acceptance\\s+criteria\\*\\*" ] }
},
"tiers": [
{ "when": { "type": "all", "conditions": [ { "type": "ref", "name": "isInvestigation" }, { "type": "measure", "measure": "context", "atLeast": 2 } ] }, "score": 100, "finding": "✓ Investigation Context: Well documented" },
Expand Down
Loading