Skip to content

Commit

Permalink
fix: example-value-or-externalValue too broad JsonPath expressions (#899
Browse files Browse the repository at this point in the history
)

* fix: $..examples is too broad (#883)

* Added examples for headers.

* Fix existing tests

* Added new tests

* A little more fine-grained JSON paths

Co-authored-by: Jakub Rożek <[email protected]>
Co-authored-by: Vincenzo Chianese <[email protected]>
  • Loading branch information
3 people committed Jan 14, 2020
1 parent 62f1618 commit d391292
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 34 deletions.
221 changes: 188 additions & 33 deletions src/rulesets/oas/__tests__/example-value-or-externalValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,82 @@ describe('example-value-or-externalValue', () => {
});

test('validate if just externalValue', async () => {
const results = await s.run({ examples: { first: { externalValue: 'value' } } });
const results = await s.run({ components: { examples: { first: { externalValue: 'value' } } } });
expect(results.length).toEqual(0);
});

test('validate if just value', async () => {
const results = await s.run({ examples: { first: { value: 'value' } } });
const results = await s.run({ components: { examples: { first: { value: 'value' } } } });
expect(results.length).toEqual(0);
});

test('validate if example on top level', async () => {
const results = await s.run({ examples: { first: { value: 'value', externalValue: 'value' } } });
expect(results.length).toEqual(0);
});

test('validate if examples properties in examples', async () => {
const results = await s.run({
components: {
examples: {
first: {
value: {
examples: {
a: 'b',
},
},
},
second: {
value: {
components: {
examples: {
value: 'value',
externalValue: 'value',
},
},
},
},
third: {
value: {
examples: {
a: 'b',
},
},
},
},
},
});
expect(results.length).toEqual(0);
});

test('multiple examples - validate all value or externalValue', async () => {
const results = await s.run({
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2' },
third: { value: 'value3' },
components: {
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2' },
third: { value: 'value3' },
},
},
});
expect(results.length).toEqual(0);
});

test('return warnings if missing externalValue and value', async () => {
const results = await s.run({ examples: { first: {} } });
const results = await s.run({ components: { examples: { first: {} } } });
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['examples', 'first'],
path: ['components', 'examples', 'first'],
range: {
end: {
character: 15,
line: 2,
character: 17,
line: 3,
},
start: {
character: 12,
line: 2,
character: 14,
line: 3,
},
},
severity: DiagnosticSeverity.Warning,
Expand All @@ -56,20 +97,108 @@ describe('example-value-or-externalValue', () => {

test('multiple examples - return warnings if missing externalValue and value in one', async () => {
const results = await s.run({
examples: { first: { value: 'value1' }, second: { externalValue: 'external-value2' }, third: {} },
components: { examples: { first: { value: 'value1' }, second: { externalValue: 'external-value2' }, third: {} } },
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['examples', 'third'],
path: ['components', 'examples', 'third'],
range: {
end: {
character: 15,
character: 17,
line: 9,
},
start: {
character: 14,
line: 9,
},
},
severity: DiagnosticSeverity.Warning,
},
]);
});

test('return warnings if both externalValue and value', async () => {
const results = await s.run({
components: { examples: { first: { externalValue: 'externalValue', value: 'value' } } },
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['components', 'examples', 'first'],
range: {
end: {
character: 24,
line: 5,
},
start: {
character: 14,
line: 3,
},
},
severity: DiagnosticSeverity.Warning,
},
]);
});

test('multiple examples - return warnings if both externalValue and value in one (in components)', async () => {
const results = await s.run({
components: {
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2', value: 'value2' },
third: { externalValue: 'external-value3' },
},
},
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['components', 'examples', 'second'],
range: {
end: {
character: 25,
line: 8,
},
start: {
character: 12,
character: 15,
line: 6,
},
},
severity: DiagnosticSeverity.Warning,
},
]);
});

test('multiple examples - return warnings if both externalValue and value in one (in headers)', async () => {
const results = await s.run({
components: {
headers: {
headerName: {
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2', value: 'value2' },
third: { externalValue: 'external-value3' },
},
},
},
},
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['components', 'headers', 'headerName', 'examples', 'second'],
range: {
end: {
character: 29,
line: 10,
},
start: {
character: 19,
line: 8,
},
},
Expand All @@ -78,49 +207,75 @@ describe('example-value-or-externalValue', () => {
]);
});

test('return warnings if both externalValue and value', async () => {
const results = await s.run({ examples: { first: { externalValue: 'externalValue', value: 'value' } } });
test('multiple examples - return warnings if both externalValue and value in one (in parameters)', async () => {
const results = await s.run({
components: {
parameters: {
parameterName: {
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2', value: 'value2' },
third: { externalValue: 'external-value3' },
},
},
},
},
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['examples', 'first'],
path: ['components', 'parameters', 'parameterName', 'examples', 'second'],
range: {
end: {
character: 22,
line: 4,
character: 29,
line: 10,
},
start: {
character: 12,
line: 2,
character: 19,
line: 8,
},
},
severity: DiagnosticSeverity.Warning,
},
]);
});

test('multiple examples - return warnings if both externalValue and value in one', async () => {
test('multiple examples - return warnings if both externalValue and value in one (in content)', async () => {
const results = await s.run({
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2', value: 'value2' },
third: { externalValue: 'external-value3' },
paths: {
'/path': {
get: {
responses: {
200: {
content: {
'application/json': {
examples: {
first: { value: 'value1' },
second: { externalValue: 'external-value2', value: 'value2' },
third: { externalValue: 'external-value3' },
},
},
},
},
},
},
},
},
});
expect(results).toEqual([
{
code: 'example-value-or-externalValue',
message: 'Example should have either a `value` or `externalValue` field.',
path: ['examples', 'second'],
path: ['paths', '/path', 'get', 'responses', '200', 'content', 'application/json', 'examples', 'second'],
range: {
end: {
character: 23,
line: 7,
character: 37,
line: 14,
},
start: {
character: 13,
line: 5,
character: 27,
line: 12,
},
},
severity: DiagnosticSeverity.Warning,
Expand Down
10 changes: 9 additions & 1 deletion src/rulesets/oas/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,15 @@
"description": "Example should have either a `value` or `externalValue` field.",
"recommended": true,
"type": "style",
"given": "$..examples.*",
"given": [
"$.components.examples.*",
"$.paths..content.*.examples.*",
"$.components..content.*.examples.*",
"$.paths..parameters.*.examples.*",
"$.components..parameters.*.examples.*",
"$.paths..headers.*.examples.*",
"$.components..headers.*.examples.*"
],
"then": {
"function": "xor",
"functionOptions": {
Expand Down

0 comments on commit d391292

Please sign in to comment.