Skip to content

Commit

Permalink
feat(oas): add rule to detect duplicated entry in enum (#1485)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amachua authored and P0lip committed Mar 8, 2021
1 parent 44928a1 commit 1f01123
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 1 deletion.
38 changes: 38 additions & 0 deletions docs/reference/openapi-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,44 @@ TheBadModel:
- 8
```

### duplicated-entry-in-enum

Each value of an `enum` must be different from one another.

**Recommended:** Yes

**Good Example**

```yaml
TheGoodModel:
type: object
properties:
number_of_connectors:
type: integer
description: The number of extension points.
enum:
- 1
- 2
- 4
- 8
```

**Bad Example**

```yaml
TheBadModel:
type: object
properties:
number_of_connectors:
type: integer
description: The number of extension points.
enum:
- 1
- 2
- 3
- 2
```

## OpenAPI v2.0-only

These rules will only apply to OpenAPI v2.0 documents.
Expand Down
117 changes: 117 additions & 0 deletions src/rulesets/oas/__tests__/duplicated-entry-in-enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { DiagnosticSeverity } from '@stoplight/types';
import * as ruleset from '../index.json';
import { RuleType, Spectral } from '../../../spectral';

describe('duplicated-entry-in-enum', () => {
const s = new Spectral();
s.setRules({
'duplicated-entry-in-enum': Object.assign(ruleset.rules['duplicated-entry-in-enum'], {
recommended: true,
type: RuleType[ruleset.rules['duplicated-entry-in-enum'].type],
}),
});

describe('oas2', () => {
test('does not report anything for empty object', async () => {
const results = await s.run({
swagger: '2.0',
});

expect(results).toEqual([]);
});

test('does not report anything when the model valid', async () => {
const doc = {
swagger: '2.0',
definitions: {
Test: {
type: 'integer',
enum: [1, 2, 3],
},
},
};

const results = await s.run(doc);

expect(results).toEqual([]);
});

test('identifies enum with duplicated entries', async () => {
const doc = {
swagger: '2.0',
definitions: {
Test: {
type: 'integer',
enum: [1, 2, 3, 4, 5, 2],
},
},
};

const results = await s.run(doc);

expect(results).toEqual([
{
code: 'duplicated-entry-in-enum',
message: `A duplicated entry in the enum was found. Error: \`enum\` property should not have duplicate items (items ## 1 and 5 are identical)`,
path: ['definitions', 'Test', 'enum'],
range: expect.any(Object),
severity: DiagnosticSeverity.Warning,
},
]);
});
});

describe('oas3', () => {
test('does not report anything for empty object', async () => {
const results = await s.run({
openapi: '3.0.0',
});

expect(results).toEqual([]);
});

test('does not report anything when the model is valid', async () => {
const doc = {
openapi: '3.0.0',
components: {
schemas: {
Test: {
type: 'integer',
enum: [1, 2, 3],
},
},
},
};

const results = await s.run(doc);

expect(results).toEqual([]);
});

test('identifies enum with duplicated entries', async () => {
const doc = {
openapi: '3.0.0',
components: {
schemas: {
Test: {
type: 'integer',
enum: [1, 2, 3, 4, 5, 2],
},
},
},
};

const results = await s.run(doc);

expect(results).toEqual([
{
code: 'duplicated-entry-in-enum',
message: `A duplicated entry in the enum was found. Error: \`enum\` property should not have duplicate items (items ## 1 and 5 are identical)`,
path: ['components', 'schemas', 'Test', 'enum'],
range: expect.any(Object),
severity: DiagnosticSeverity.Warning,
},
]);
});
});
});
17 changes: 17 additions & 0 deletions src/rulesets/oas/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,23 @@
}
]
},
"duplicated-entry-in-enum": {
"description": "Enum values should not have duplicate entry.",
"type": "validation",
"severity": 1,
"recommended": true,
"message": "A duplicated entry in the enum was found. Error: {{error}}",
"given": "$..enum",
"then": {
"function": "schema",
"functionOptions": {
"schema": {
"type": "array",
"uniqueItems": true
}
}
}
},
"info-contact": {
"description": "Info object should contain `contact` object.",
"recommended": true,
Expand Down
33 changes: 33 additions & 0 deletions test-harness/scenarios/duplicated-entry-in-enum.oas.scenario
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
====test====
Identify enum values that does not respect the specified type
====asset:ruleset====
extends: [[spectral:oas, off]]

rules:
duplicated-entry-in-enum: error
====document====
openapi: 3.0.2
components:
schemas:
a_model:
type: object
properties:
id:
type: integer
description: Unique asset identifier
enum:
- 1
- 2
- 3
- 4
- 5
- 2
====command====
{bin} lint {document} --ruleset {asset:ruleset}
====stdout====
OpenAPI 3.x detected

{document}
10:16 error duplicated-entry-in-enum A duplicated entry in the enum was found. Error: `enum` property should not have duplicate items (items ## 1 and 5 are identical) components.schemas.a_model.properties.id.enum

✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints)
2 changes: 1 addition & 1 deletion test-harness/scenarios/enabled-rules-amount.oas3.scenario
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ components:
====command====
{bin} lint {document} --ruleset ./rulesets/parameter-description.oas3.yaml -v
====stdout====
Found 55 rules (1 enabled)
Found 56 rules (1 enabled)
Linting {document}
OpenAPI 3.x detected

Expand Down

0 comments on commit 1f01123

Please sign in to comment.