Repository: stoplightio/spectral
Pull request #1313 (2020-08-26 15:39:17)

feat(oas): merge example rules
This is a follow-up PR.
See https://github.com/stoplightio/spectral/pull/1284#issuecomment-678874684 for the reasoning.

tl;dr we no longer need such granular rules, as `given` can be an array of paths now.



**Checklist**

- [x] Tests added / updated
- [x] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No




nulltoken: @P0lip Great job! One thought though. There are a lot of code duplication among the tests, and some tests exist in some file and not in others (`format` related ones IIRC for instance). 

What would you think of extracting the valid/invalid schemas and the matching props of the results we'd like to check in one global collection, and then "inject" the schemas in proper locations of base documents in each test? We may have to tweak the expectations regarding the resulting paths, but it's possible this would greatly reduce the size of the diff and (maybe) make those tests a bit easier to maintain and reason about?
P0lip: Agree re duplication. It bothers me too.

> What would you think of extracting the valid/invalid schemas and the matching props of the results we'd like to check in one global collection, and then "inject" the schemas in proper locations of base documents in each test?

Hm, not sure I'm following. What do you exactly suggest?


philsturgeon: There's a few approaches to avoid duplication: 

1. [jest.each](https://blog.theodo.com/2018/09/jest-each-tests/)
2. defining common schema in a context (outside of it()) and just tweaking it a bit for each one, instead of redefining the whole thing
3. make some "fixture files"

I'm usually quite content with 1 or 2 but 3 can lead to awkward changes when multiple people do different things with the fixtures. 

Also keep in mind we don't need to fix this now, if we keep on boy scouting as we go it'll get better over time. 
nulltoken: @P0lip My thoughts were around a combination of @philsturgeon points 1 & 2. However, I'm also fine with the `we don't need to fix this now, if we keep on boy scouting as we go it'll get better over time` way. You've done a tremendous job and maybe refactoring the examples would just deserve a neat issue to keep track of it
P0lip: @nulltoken @philsturgeon alright, did some deduplication.
We could probably do a little bit more here and there, but it should be already much better

Patch:
diff --git a/src/rulesets/oas/index.json b/src/rulesets/oas/index.json
index 556ab6bd..98f9e571 100644
--- a/src/rulesets/oas/index.json
+++ b/src/rulesets/oas/index.json
@@ -400,32 +400,19 @@
         }
       }
     },
-    "oas2-valid-parameter-example": {
+    "oas2-valid-schema-example": {
       "description": "Examples must be valid against their defined schema.",
       "message": "{{error}}",
       "recommended": true,
       "formats": ["oas2"],
       "severity": 0,
       "type": "validation",
-      "given": "$..parameters..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "$",
-          "oasVersion": 2,
-          "type": "schema"
-        }
-      }
-    },
-    "oas2-valid-definition-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "formats": ["oas2"],
-      "severity": 0,
-      "type": "validation",
-      "given": "$..definitions..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]",
-      "then": {
+      "given": [
+        "$..definitions..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]",
+        "$..parameters..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]",
+        "$..responses..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]"
+      ],
+        "then": {
         "function": "oasExample",
         "functionOptions": {
           "schemaField": "$",
@@ -434,7 +421,7 @@
         }
       }
     },
-    "oas2-valid-response-example": {
+    "oas2-valid-media-example": {
       "description": "Examples must be valid against their defined schema.",
       "message": "{{error}}",
       "recommended": true,
@@ -451,23 +438,6 @@
         }
       }
     },
-    "oas2-valid-response-schema-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "formats": ["oas2"],
-      "severity": 0,
-      "type": "validation",
-      "given": "$..responses..[?(@property !== 'properties' && (@.example || @['x-example']) && (@.type || @.format || @.$ref || @.properties || @.items))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "$",
-          "oasVersion": 2,
-          "type": "schema"
-        }
-      }
-    },
     "oas2-anyOf": {
       "description": "OpenAPI v3 keyword `anyOf` detected in OpenAPI v2 document.",
       "message": "anyOf is not available in OpenAPI v2, it was added in OpenAPI v3",
@@ -614,48 +584,18 @@
         }
       }
     },
-    "oas3-valid-oas-parameter-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "severity": 0,
-      "formats": ["oas3"],
-      "type": "validation",
-      "given": "$..parameters..[?(@.schema && (@.example || @.examples))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "schema",
-          "oasVersion": 3,
-          "type": "media"
-        }
-      }
-    },
-    "oas3-valid-oas-header-example": {
+    "oas3-valid-media-example": {
       "description": "Examples must be valid against their defined schema.",
       "message": "{{error}}",
       "recommended": true,
       "severity": 0,
       "formats": ["oas3"],
       "type": "validation",
-      "given": "$..headers..[?(@.schema && (@.example || @.examples))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "schema",
-          "oasVersion": 3,
-          "type": "media"
-        }
-      }
-    },
-    "oas3-valid-oas-content-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "severity": 0,
-      "formats": ["oas3"],
-      "type": "validation",
-      "given": "$..content..[?(@.schema && (@.example || @.examples))]",
+      "given": [
+        "$..content..[?(@.schema && (@.example || @.examples))]",
+        "$..headers..[?(@.schema && (@.example || @.examples))]",
+        "$..parameters..[?(@.schema && (@.example || @.examples))]"
+      ],
       "then": {
         "function": "oasExample",
         "functionOptions": {
@@ -665,40 +605,6 @@
         }
       }
     },
-    "oas3-valid-parameter-schema-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "severity": 0,
-      "formats": ["oas3"],
-      "type": "validation",
-      "given": "$..parameters..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "$",
-          "oasVersion": 3,
-          "type": "schema"
-        }
-      }
-    },
-    "oas3-valid-header-schema-example": {
-      "description": "Examples must be valid against their defined schema.",
-      "message": "{{error}}",
-      "recommended": true,
-      "severity": 0,
-      "formats": ["oas3"],
-      "type": "validation",
-      "given": "$..headers..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]",
-      "then": {
-        "function": "oasExample",
-        "functionOptions": {
-          "schemaField": "$",
-          "oasVersion": 3,
-          "type": "schema"
-        }
-      }
-    },
     "oas3-valid-schema-example": {
       "description": "Examples must be valid against their defined schema.",
       "message": "{{error}}",
@@ -708,7 +614,9 @@
       "type": "validation",
       "given": [
         "$.components.schemas..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]",
-        "$..content..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]"
+        "$..content..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]",
+        "$..headers..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]",
+        "$..parameters..[?(@property !== 'properties' && @.example && (@.type || @.format || @.$ref || @.properties || @.items))]"
       ],
       "then": {
         "function": "oasExample",


Test patch:
diff --git a/src/rulesets/oas/__tests__/oas2-valid-definition-example.ts b/src/rulesets/oas/__tests__/oas2-valid-definition-example.ts
deleted file mode 100644
index 3a85ca44..00000000
--- a/src/rulesets/oas/__tests__/oas2-valid-definition-example.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../spectral';
-import * as ruleset from '../index.json';
-import oasExample from '../functions/oasExample';
-import { setFunctionContext } from '../../evaluators';
-import { functions } from '../../../functions';
-
-describe('oas2-valid-definition-example', () => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas2', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      'oas2-valid-definition-example': Object.assign(ruleset.rules['oas2-valid-definition-example'], {
-        recommended: true,
-        type: RuleType[ruleset.rules['oas2-valid-definition-example'].type],
-      }),
-    });
-  });
-
-  test.each(['example', 'x-example'])('will pass when simple %s is valid', async field => {
-    const results = await s.run({
-      definitions: [
-        {
-          xoxo: {
-            type: 'string',
-            [field]: 'doggie',
-          },
-        },
-      ],
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test.each(['example', 'x-example'])('will fail when simple %s is invalid', async field => {
-    const results = await s.run({
-      definitions: [
-        {
-          xoxo: {
-            type: 'string',
-            [field]: 123,
-          },
-        },
-      ],
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-definition-example',
-        message: `\`${field}\` property type should be string`,
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      definitions: {
-        xoxo: {
-          type: 'object',
-          properties: {
-            url: {
-              type: 'string',
-            },
-            width: {
-              type: 'integer',
-            },
-            height: {
-              type: 'integer',
-            },
-          },
-          required: ['url'],
-          example: {
-            url: 'images/38.png',
-            width: 100,
-            height: 100,
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      definitions: {
-        xoxo: {
-          type: 'object',
-          properties: {
-            url: {
-              type: 'string',
-            },
-            width: {
-              type: 'integer',
-            },
-            height: {
-              type: 'integer',
-            },
-          },
-          required: ['url'],
-          example: {
-            url2: 'images/38.png',
-            width: 'coffee',
-            height: false,
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-definition-example',
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('works fine with allOf $ref', async () => {
-    const results = await s.run({
-      definitions: {
-        halRoot: {
-          type: 'object',
-          allOf: [
-            {
-              $ref: '#/definitions/halResource',
-            },
-          ],
-          example: {
-            _links: {
-              self: {
-                href: '/',
-              },
-              products: {
-                href: '/products',
-              },
-              product: {
-                href: '/products/{product_id}',
-              },
-              users: {
-                href: '/users',
-              },
-            },
-          },
-        },
-        halResource: {
-          title: 'HAL Resource Object',
-          type: 'object',
-          properties: {
-            _links: {
-              type: 'object',
-              additionalProperties: {
-                allOf: [
-                  {
-                    $ref: '#/definitions/halLinkObject',
-                  },
-                  {
-                    type: 'array',
-                    items: [
-                      {
-                        $ref: '#/definitions/halLinkObject',
-                      },
-                    ],
-                  },
-                ],
-              },
-            },
-            _embedded: {
-              type: 'object',
-              additionalProperties: true,
-            },
-          },
-        },
-        halLinkObject: {
-          type: 'object',
-          required: ['href'],
-          properties: {
-            href: {
-              type: 'string',
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: 'oas2-valid-definition-example',
-        message: '`self` property type should be array',
-        path: ['definitions', 'halRoot', 'example', '_links', 'self'],
-      }),
-    ]);
-  });
-
-  test('will pass for valid parents examples which contain invalid child examples', async () => {
-    const results = await s.run({
-      definitions: [
-        {
-          xoxo: {
-            type: 'object',
-            example: {
-              a: {
-                b: {
-                  c: 'foo',
-                },
-              },
-            },
-            properties: {
-              a: {
-                type: 'object',
-                example: {
-                  b: {
-                    c: 'foo',
-                  },
-                },
-                properties: {
-                  b: {
-                    type: 'object',
-                    properties: {
-                      c: {
-                        type: 'string',
-                        example: 12345,
-                      },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        },
-      ],
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-definition-example',
-        message: '`example` property type should be string',
-        path: ['definitions', '0', 'xoxo', 'properties', 'a', 'properties', 'b', 'properties', 'c', 'example'],
-        range: expect.any(Object),
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will not fail if an actual property is called example', async () => {
-    const results = await s.run({
-      definitions: {
-        xoxo: {
-          type: 'object',
-          properties: {
-            example: {
-              description: 'an actual field called example...',
-              type: 'string',
-            },
-          },
-          example: {
-            example: 'what is gonna happen',
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will not fail if an actual property is called example and there is also type/format property', async () => {
-    const results = await s.run({
-      definitions: {
-        xoxo: {
-          type: 'object',
-          properties: {
-            example: {
-              type: 'string',
-              example: 'abc',
-            },
-            type: {
-              type: 'number',
-              example: 123,
-            },
-            format: 'plain text',
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-});
diff --git a/src/rulesets/oas/__tests__/oas2-valid-media-example.ts b/src/rulesets/oas/__tests__/oas2-valid-media-example.ts
new file mode 100644
index 00000000..5c197f47
--- /dev/null
+++ b/src/rulesets/oas/__tests__/oas2-valid-media-example.ts
@@ -0,0 +1,65 @@
+import { DiagnosticSeverity } from '@stoplight/types';
+import { RuleType, Spectral } from '../../../spectral';
+import * as ruleset from '../index.json';
+import { setFunctionContext } from '../../evaluators';
+import { functions } from '../../../functions';
+import oasExample from '../functions/oasExample';
+
+describe('oas2-valid-media-example', () => {
+  let s: Spectral;
+
+  beforeEach(() => {
+    s = new Spectral();
+    s.registerFormat('oas2', () => true);
+    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
+    s.setRules({
+      'oas2-valid-media-example': Object.assign(ruleset.rules['oas2-valid-media-example'], {
+        recommended: true,
+        type: RuleType[ruleset.rules['oas2-valid-media-example'].type],
+      }),
+    });
+  });
+
+  describe('responses', () => {
+    test('will pass when examples are valid', async () => {
+      const results = await s.run({
+        responses: {
+          200: {
+            schema: {
+              type: 'string',
+            },
+            examples: {
+              'application/json': 'test',
+              'application/yaml': '',
+            },
+          },
+        },
+      });
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when example is invalid', async () => {
+      const results = await s.run({
+        responses: {
+          200: {
+            schema: {
+              type: 'string',
+            },
+            examples: {
+              'application/json': 'test',
+              'application/yaml': 2,
+            },
+          },
+        },
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas2-valid-media-example',
+          message: '`application/yaml` property type should be string',
+          severity: DiagnosticSeverity.Error,
+          path: ['responses', '200', 'examples', 'application/yaml'],
+        }),
+      ]);
+    });
+  });
+});
diff --git a/src/rulesets/oas/__tests__/oas2-valid-parameter-example.ts b/src/rulesets/oas/__tests__/oas2-valid-parameter-example.ts
deleted file mode 100644
index 44362828..00000000
--- a/src/rulesets/oas/__tests__/oas2-valid-parameter-example.ts
+++ /dev/null
@@ -1,256 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../spectral';
-import * as ruleset from '../index.json';
-import { setFunctionContext } from '../../evaluators';
-import { functions } from '../../../functions';
-import oasExample from '../functions/oasExample';
-
-describe('oas2-valid-parameter-example', () => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas2', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      'oas2-valid-parameter-example': Object.assign(ruleset.rules['oas2-valid-parameter-example'], {
-        recommended: true,
-        type: RuleType[ruleset.rules['oas2-valid-parameter-example'].type],
-      }),
-    });
-  });
-
-  test.each(['example', 'x-example'])('will pass when %s example is valid', async field => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          schema: {
-            type: 'string',
-            [field]: 'doggie',
-          },
-        },
-      ],
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test.each(['example', 'x-example'])('will fail when %s example is invalid', async field => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          schema: {
-            type: 'string',
-            [field]: 123,
-          },
-        },
-      ],
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-parameter-example',
-        message: `\`${field}\` property type should be string`,
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url: 'images/38.png',
-              width: 100,
-              height: 100,
-            },
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url2: 'images/38.png',
-              width: 'coffee',
-              height: false,
-            },
-          },
-        },
-      ],
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-parameter-example',
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will pass for valid parents examples which contain invalid child examples', async () => {
-    const results = await s.run({
-      swagger: '2.0',
-      info: {
-        version: '1.0.0',
-        title: 'Swagger Petstore',
-      },
-      paths: {
-        '/pet': {
-          post: {
-            parameters: [
-              {
-                in: 'body',
-                name: 'body',
-                required: true,
-                schema: {
-                  type: 'object',
-                  example: {
-                    a: {
-                      b: {
-                        c: 'foo',
-                      },
-                    },
-                  },
-                  properties: {
-                    a: {
-                      type: 'object',
-                      example: {
-                        b: {
-                          c: 'foo',
-                        },
-                      },
-                      properties: {
-                        b: {
-                          type: 'object',
-                          properties: {
-                            c: {
-                              type: 'string',
-                              example: 12345,
-                            },
-                          },
-                        },
-                      },
-                    },
-                  },
-                },
-              },
-            ],
-            responses: {
-              '200': {
-                description: 'OK',
-              },
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-parameter-example',
-        message: '`example` property type should be string',
-        path: [
-          'paths',
-          '/pet',
-          'post',
-          'parameters',
-          '0',
-          'schema',
-          'properties',
-          'a',
-          'properties',
-          'b',
-          'properties',
-          'c',
-          'example',
-        ],
-        range: expect.any(Object),
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will not fail if an actual property is called example', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          type: 'object',
-          properties: {
-            example: {
-              description: 'an actual field called example...',
-              type: 'string',
-            },
-          },
-          example: {
-            example: 'what is gonna happen',
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will not fail if an actual property is called example and there is also type/format property', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          type: 'object',
-          properties: {
-            example: {
-              type: 'string',
-              example: 'abc',
-            },
-            type: {
-              type: 'number',
-              example: 123,
-            },
-            format: 'plain text',
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-});
diff --git a/src/rulesets/oas/__tests__/oas2-valid-response-example.ts b/src/rulesets/oas/__tests__/oas2-valid-response-example.ts
deleted file mode 100644
index d3d6d6d2..00000000
--- a/src/rulesets/oas/__tests__/oas2-valid-response-example.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../spectral';
-import * as ruleset from '../index.json';
-import { setFunctionContext } from '../../evaluators';
-import { functions } from '../../../functions';
-import oasExample from '../functions/oasExample';
-
-describe('oas2-valid-response-example', () => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas2', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      'oas2-valid-response-example': Object.assign(ruleset.rules['oas2-valid-response-example'], {
-        recommended: true,
-        type: RuleType[ruleset.rules['oas2-valid-parameter-example'].type],
-      }),
-    });
-  });
-
-  test('will pass when examples are valid', async () => {
-    const results = await s.run({
-      responses: {
-        200: {
-          schema: {
-            type: 'string',
-          },
-          examples: {
-            'application/json': 'test',
-            'application/yaml': '',
-          },
-        },
-      },
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when example is invalid', async () => {
-    const results = await s.run({
-      responses: {
-        200: {
-          schema: {
-            type: 'string',
-          },
-          examples: {
-            'application/json': 'test',
-            'application/yaml': 2,
-          },
-        },
-      },
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas2-valid-response-example',
-        message: '`application/yaml` property type should be string',
-        severity: DiagnosticSeverity.Error,
-        path: ['responses', '200', 'examples', 'application/yaml'],
-      }),
-    ]);
-  });
-});
diff --git a/src/rulesets/oas/__tests__/oas2-valid-schema-example.ts b/src/rulesets/oas/__tests__/oas2-valid-schema-example.ts
new file mode 100644
index 00000000..132040b2
--- /dev/null
+++ b/src/rulesets/oas/__tests__/oas2-valid-schema-example.ts
@@ -0,0 +1,302 @@
+import { DiagnosticSeverity } from '@stoplight/types';
+import { RuleType, Spectral } from '../../../spectral';
+import * as ruleset from '../index.json';
+import { setFunctionContext } from '../../evaluators';
+import { functions } from '../../../functions';
+import oasExample from '../functions/oasExample';
+
+describe('oas2-valid-schema-example', () => {
+  let s: Spectral;
+
+  beforeEach(() => {
+    s = new Spectral();
+    s.registerFormat('oas2', () => true);
+    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
+    s.setRules({
+      'oas2-valid-schema-example': Object.assign(ruleset.rules['oas2-valid-schema-example'], {
+        recommended: true,
+        type: RuleType[ruleset.rules['oas2-valid-schema-example'].type],
+      }),
+    });
+  });
+
+  describe.each(['parameters', 'definitions'])('%s', parentField => {
+    test.each(['example', 'x-example'])('will pass when %s example is valid', async field => {
+      const results = await s.run({
+        [parentField]: [
+          {
+            in: 'body',
+            schema: {
+              type: 'string',
+              [field]: 'doggie',
+            },
+          },
+        ],
+      });
+      expect(results).toHaveLength(0);
+    });
+
+    test.each(['example', 'x-example'])('will fail when simple %s is invalid', async field => {
+      const results = await s.run({
+        [parentField]: [
+          {
+            xoxo: {
+              type: 'string',
+              [field]: 123,
+            },
+          },
+        ],
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas2-valid-schema-example',
+          message: `\`${field}\` property type should be string`,
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will pass when complex example is used ', async () => {
+      const results = await s.run({
+        [parentField]: [
+          {
+            in: 'body',
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+              example: {
+                url: 'images/38.png',
+                width: 100,
+                height: 100,
+              },
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will error with totally invalid input', async () => {
+      const results = await s.run({
+        [parentField]: [
+          {
+            in: 'body',
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+              example: {
+                url2: 'images/38.png',
+                width: 'coffee',
+                height: false,
+              },
+            },
+          },
+        ],
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas2-valid-schema-example',
+          message: '`example` property should have required property `url`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will not fail if an actual property is called example and there is also type/format property', async () => {
+      const results = await s.run({
+        [parentField]: [
+          {
+            type: 'object',
+            properties: {
+              example: {
+                type: 'string',
+                example: 'abc',
+              },
+              type: {
+                type: 'number',
+                example: 123,
+              },
+              format: 'plain text',
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+  });
+
+  describe('definitions', () => {
+    test('works fine with allOf $ref', async () => {
+      const results = await s.run({
+        definitions: {
+          halRoot: {
+            type: 'object',
+            allOf: [
+              {
+                $ref: '#/definitions/halResource',
+              },
+            ],
+            example: {
+              _links: {
+                self: {
+                  href: '/',
+                },
+                products: {
+                  href: '/products',
+                },
+                product: {
+                  href: '/products/{product_id}',
+                },
+                users: {
+                  href: '/users',
+                },
+              },
+            },
+          },
+          halResource: {
+            title: 'HAL Resource Object',
+            type: 'object',
+            properties: {
+              _links: {
+                type: 'object',
+                additionalProperties: {
+                  allOf: [
+                    {
+                      $ref: '#/definitions/halLinkObject',
+                    },
+                    {
+                      type: 'array',
+                      items: [
+                        {
+                          $ref: '#/definitions/halLinkObject',
+                        },
+                      ],
+                    },
+                  ],
+                },
+              },
+              _embedded: {
+                type: 'object',
+                additionalProperties: true,
+              },
+            },
+          },
+          halLinkObject: {
+            type: 'object',
+            required: ['href'],
+            properties: {
+              href: {
+                type: 'string',
+              },
+            },
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas2-valid-schema-example',
+          message: '`self` property type should be array',
+          path: ['definitions', 'halRoot', 'example', '_links', 'self'],
+        }),
+      ]);
+    });
+
+    test('will fail for valid parents examples which contain invalid child examples', async () => {
+      const results = await s.run({
+        definitions: [
+          {
+            xoxo: {
+              type: 'object',
+              example: {
+                a: {
+                  b: {
+                    c: 'foo',
+                  },
+                },
+              },
+              properties: {
+                a: {
+                  type: 'object',
+                  example: {
+                    b: {
+                      c: 'foo',
+                    },
+                  },
+                  properties: {
+                    b: {
+                      type: 'object',
+                      properties: {
+                        c: {
+                          type: 'string',
+                          example: 12345,
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+          },
+        ],
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas2-valid-schema-example',
+          message: '`example` property type should be string',
+          path: ['definitions', '0', 'xoxo', 'properties', 'a', 'properties', 'b', 'properties', 'c', 'example'],
+          range: expect.any(Object),
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will not fail if an actual property is called example', async () => {
+      const results = await s.run({
+        definitions: {
+          xoxo: {
+            type: 'object',
+            properties: {
+              example: {
+                description: 'an actual field called example...',
+                type: 'string',
+              },
+            },
+            example: {
+              example: 'what is gonna happen',
+            },
+          },
+        },
+      });
+
+      expect(results).toHaveLength(0);
+    });
+  });
+});
diff --git a/src/rulesets/oas/__tests__/oas3-valid-header-schema-example.ts b/src/rulesets/oas/__tests__/oas3-valid-header-schema-example.ts
deleted file mode 100644
index 674b0e3d..00000000
--- a/src/rulesets/oas/__tests__/oas3-valid-header-schema-example.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import testRule from './templates/_schema-example';
-
-const ruleName = 'oas3-valid-header-schema-example';
-
-describe(ruleName, () => testRule(ruleName, 'headers'));
diff --git a/src/rulesets/oas/__tests__/oas3-valid-media-example.test.ts b/src/rulesets/oas/__tests__/oas3-valid-media-example.test.ts
new file mode 100644
index 00000000..3c67a064
--- /dev/null
+++ b/src/rulesets/oas/__tests__/oas3-valid-media-example.test.ts
@@ -0,0 +1,432 @@
+import { DiagnosticSeverity } from '@stoplight/types';
+import { RuleType, Spectral } from '../../../spectral';
+import { rules } from '../index.json';
+import { setFunctionContext } from '../../evaluators';
+import { functions } from '../../../functions';
+import oasExample from '../functions/oasExample';
+
+describe('oas3-valid-media-example', () => {
+  let s: Spectral;
+
+  beforeEach(() => {
+    s = new Spectral();
+    s.registerFormat('oas3', () => true);
+    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
+    s.setRules({
+      ['oas3-valid-media-example']: Object.assign(rules['oas3-valid-media-example'], {
+        recommended: true,
+        type: RuleType[rules['oas3-valid-media-example'].type],
+      }),
+    });
+  });
+
+  describe.each(['headers', 'content'])('%s', path => {
+    test('will pass when simple example is valid', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'string',
+            },
+            example: 'doggie',
+          },
+        },
+      });
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when simple example is invalid', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'string',
+            },
+            example: 123,
+          },
+        },
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-media-example',
+          message: '`example` property type should be string',
+        }),
+      ]);
+    });
+
+    test('will pass when complex example is used ', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+            },
+            example: {
+              url: 'images/38.png',
+              width: 100,
+              height: 100,
+            },
+          },
+        },
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when complex example is used ', async () => {
+      const data = {
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'number',
+            },
+            example: 4,
+          },
+          abc: {
+            schema: {
+              type: 'object',
+              properties: {
+                id: {
+                  type: 'integer',
+                  format: 'int64',
+                },
+                name: {
+                  type: 'string',
+                },
+                abc: {
+                  type: 'number',
+                  example: '5',
+                },
+              },
+              required: ['name'],
+            },
+            example: {
+              name: 'Puma',
+              id: 1,
+            },
+          },
+        },
+      };
+
+      const results = await s.run(data);
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will error with totally invalid input', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+                email: {
+                  type: 'string',
+                  format: 'email',
+                },
+              },
+              required: ['url'],
+            },
+            example: {
+              url2: 'images/38.png',
+              width: 'coffee',
+              height: false,
+              email: 123,
+            },
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-media-example',
+          message: '`example` property should have required property `url`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('does not report example mismatches for unknown AJV formats', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'string',
+              format: 'foo',
+            },
+            example: 'abc',
+          },
+        },
+      });
+
+      expect(results).toEqual([]);
+    });
+
+    test.each([
+      ['byte', '1'],
+      ['int32', 2 ** 31],
+      ['int64', 2 ** 63],
+      ['float', 2 ** 128],
+    ])('reports invalid usage of %s format', async (format, example) => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: ['string', 'number'],
+              format,
+              properties: {
+                ip_address: {
+                  type: 'string',
+                },
+              },
+            },
+            example,
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-media-example',
+          message: `\`example\` property should match format \`${format}\``,
+        }),
+      ]);
+    });
+
+    test.each([
+      ['byte', 'MTI3'],
+      ['int32', 2 ** 30],
+      ['int64', 2 ** 40],
+      ['float', 2 ** 64],
+      ['double', 2 ** 1028],
+    ])('does not report valid usage of %s format', async (format, example) => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: ['string', 'number'],
+              format,
+              properties: {
+                ip_address: {
+                  type: 'string',
+                },
+              },
+            },
+            example,
+          },
+        },
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when simple example is invalid (examples)', async () => {
+      const results = await s.run({
+        openapi: '3.0.0',
+        [path]: {
+          xoxo: {
+            schema: {
+              type: 'string',
+            },
+            examples: {
+              test1: {
+                value: 123,
+              },
+            },
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-media-example',
+          message: '`value` property type should be string',
+        }),
+      ]);
+    });
+  });
+
+  describe('parameters', () => {
+    test('will pass when simple example is valid', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'string',
+            },
+            example: 'doggie',
+          },
+        ],
+      });
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when simple example is invalid', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'string',
+            },
+            example: 123,
+          },
+        ],
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-media-example',
+          message: '`example` property type should be string',
+        }),
+      ]);
+    });
+
+    test('will pass when complex example is used ', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+            },
+            example: {
+              url: 'images/38.png',
+              width: 100,
+              height: 100,
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when complex example is used', async () => {
+      const data = {
+        parameters: [
+          {
+            Heh: {
+              schema: {
+                type: 'number',
+              },
+              example: 4,
+            },
+            Abc: {
+              schema: {
+                type: 'object',
+                properties: {
+                  id: {
+                    type: 'integer',
+                    format: 'int64',
+                  },
+                  name: {
+                    type: 'string',
+                  },
+                  abc: {
+                    type: 'number',
+                    example: '5',
+                  },
+                },
+                required: ['abc'],
+              },
+              example: {
+                name: 'Puma',
+                id: 1,
+              },
+            },
+          },
+        ],
+      };
+
+      const results = await s.run(data);
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-media-example',
+          message: '`example` property should have required property `abc`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will error with totally invalid input', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+            },
+            example: {
+              url2: 'images/38.png',
+              width: 'coffee',
+              height: false,
+            },
+          },
+        ],
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-media-example',
+          message: '`example` property should have required property `url`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+  });
+});
diff --git a/src/rulesets/oas/__tests__/oas3-valid-oas-content-example.ts b/src/rulesets/oas/__tests__/oas3-valid-oas-content-example.ts
deleted file mode 100644
index 6929c941..00000000
--- a/src/rulesets/oas/__tests__/oas3-valid-oas-content-example.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import testRule from './templates/_oas-example';
-
-const ruleName = 'oas3-valid-oas-content-example';
-
-describe(ruleName, () => testRule(ruleName, 'content'));
diff --git a/src/rulesets/oas/__tests__/oas3-valid-oas-header-example.ts b/src/rulesets/oas/__tests__/oas3-valid-oas-header-example.ts
deleted file mode 100644
index 10569e87..00000000
--- a/src/rulesets/oas/__tests__/oas3-valid-oas-header-example.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import testRule from './templates/_oas-example';
-
-const ruleName = 'oas3-valid-oas-header-example';
-
-describe(ruleName, () => testRule(ruleName, 'headers'));
diff --git a/src/rulesets/oas/__tests__/oas3-valid-oas-parameter-example.ts b/src/rulesets/oas/__tests__/oas3-valid-oas-parameter-example.ts
deleted file mode 100644
index 7f9685de..00000000
--- a/src/rulesets/oas/__tests__/oas3-valid-oas-parameter-example.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../spectral';
-import * as ruleset from '../index.json';
-import { setFunctionContext } from '../../evaluators';
-import { functions } from '../../../functions';
-import oasExample from '../functions/oasExample';
-
-describe('oas3-valid-oas-parameter-example', () => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-
-    s.registerFormat('oas3', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      'oas3-valid-oas-parameter-example': Object.assign(ruleset.rules['oas3-valid-oas-parameter-example'], {
-        recommended: true,
-        type: RuleType[ruleset.rules['oas3-valid-oas-parameter-example'].type],
-      }),
-    });
-  });
-
-  test('will pass when simple example is valid', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'string',
-          },
-          example: 'doggie',
-        },
-      ],
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when simple example is invalid', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'string',
-          },
-          example: 123,
-        },
-      ],
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: 'oas3-valid-oas-parameter-example',
-        message: '`example` property type should be string',
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-          },
-          example: {
-            url: 'images/38.png',
-            width: 100,
-            height: 100,
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when complex example is used', async () => {
-    const data = {
-      parameters: [
-        {
-          Heh: {
-            schema: {
-              type: 'number',
-            },
-            example: 4,
-          },
-          Abc: {
-            schema: {
-              type: 'object',
-              properties: {
-                id: {
-                  type: 'integer',
-                  format: 'int64',
-                },
-                name: {
-                  type: 'string',
-                },
-                abc: {
-                  type: 'number',
-                  example: '5',
-                },
-              },
-              required: ['abc'],
-            },
-            example: {
-              name: 'Puma',
-              id: 1,
-            },
-          },
-        },
-      ],
-    };
-
-    const results = await s.run(data);
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-oas-parameter-example',
-        message: '`example` property should have required property `abc`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-          },
-          example: {
-            url2: 'images/38.png',
-            width: 'coffee',
-            height: false,
-          },
-        },
-      ],
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-oas-parameter-example',
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-});
diff --git a/src/rulesets/oas/__tests__/oas3-valid-parameter-schema-example.ts b/src/rulesets/oas/__tests__/oas3-valid-parameter-schema-example.ts
deleted file mode 100644
index 0b1cf061..00000000
--- a/src/rulesets/oas/__tests__/oas3-valid-parameter-schema-example.ts
+++ /dev/null
@@ -1,300 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../spectral';
-import * as ruleset from '../index.json';
-import { setFunctionContext } from '../../evaluators';
-import { functions } from '../../../functions';
-import oasExample from '../functions/oasExample';
-
-describe('oas3-valid-parameter-schema-example', () => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas3', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      'oas3-valid-parameter-schema-example': Object.assign(ruleset.rules['oas3-valid-parameter-schema-example'], {
-        recommended: true,
-        type: RuleType[ruleset.rules['oas3-valid-parameter-schema-example'].type],
-      }),
-    });
-  });
-
-  test('will pass when simple example is valid', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'string',
-            example: 'doggie',
-          },
-        },
-      ],
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test('will pass for valid parents examples which contain invalid child examples', async () => {
-    const results = await s.run({
-      swagger: '2.0',
-      info: {
-        version: '1.0.0',
-        title: 'Swagger Petstore',
-      },
-      paths: {
-        '/pet': {
-          post: {
-            parameters: [
-              {
-                in: 'body',
-                name: 'body',
-                required: true,
-                schema: {
-                  type: 'object',
-                  example: {
-                    a: {
-                      b: {
-                        c: 'foo',
-                      },
-                    },
-                  },
-                  properties: {
-                    a: {
-                      type: 'object',
-                      example: {
-                        b: {
-                          c: 'foo',
-                        },
-                      },
-                      properties: {
-                        b: {
-                          type: 'object',
-                          properties: {
-                            c: {
-                              type: 'string',
-                              example: 12345,
-                            },
-                          },
-                        },
-                      },
-                    },
-                  },
-                },
-              },
-            ],
-            responses: {
-              '200': {
-                description: 'OK',
-              },
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-parameter-schema-example',
-        message: '`example` property type should be string',
-        path: [
-          'paths',
-          '/pet',
-          'post',
-          'parameters',
-          '0',
-          'schema',
-          'properties',
-          'a',
-          'properties',
-          'b',
-          'properties',
-          'c',
-          'example',
-        ],
-        range: expect.any(Object),
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will not fail if an actual property is called example', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          in: 'body',
-          type: 'object',
-          properties: {
-            example: {
-              description: 'an actual field called example...',
-              type: 'string',
-            },
-          },
-          example: {
-            example: 'what is gonna happen',
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will not fail if an actual property is called example and there is also type/format property', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          type: 'object',
-          properties: {
-            example: {
-              type: 'string',
-              example: 'abc',
-            },
-            type: {
-              type: 'number',
-              example: 123,
-            },
-            format: 'plain text',
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when simple example is invalid', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'string',
-            example: 123,
-          },
-        },
-      ],
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: 'oas3-valid-parameter-schema-example',
-        message: '`example` property type should be string',
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url: 'images/38.png',
-              width: 100,
-              height: 100,
-            },
-          },
-        },
-      ],
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when complex example is used', async () => {
-    const data = {
-      parameters: [
-        {
-          Heh: {
-            schema: {
-              type: 'number',
-              example: 4,
-            },
-          },
-          Abc: {
-            schema: {
-              type: 'object',
-              properties: {
-                id: {
-                  type: 'integer',
-                  format: 'int64',
-                },
-                name: {
-                  type: 'string',
-                },
-                abc: {
-                  type: 'number',
-                  example: '5',
-                },
-              },
-              required: ['name'],
-              example: {
-                name: 'Puma',
-                id: 1,
-              },
-            },
-          },
-        },
-      ],
-    };
-
-    const results = await s.run(data);
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-parameter-schema-example',
-        message: '`example` property type should be number',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      parameters: [
-        {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url2: 'images/38.png',
-              width: 'coffee',
-              height: false,
-            },
-          },
-        },
-      ],
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-parameter-schema-example',
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-});
diff --git a/src/rulesets/oas/__tests__/oas3-valid-schema-example.ts b/src/rulesets/oas/__tests__/oas3-valid-schema-example.ts
index 0362c3d4..9e6c993a 100644
--- a/src/rulesets/oas/__tests__/oas3-valid-schema-example.ts
+++ b/src/rulesets/oas/__tests__/oas3-valid-schema-example.ts
@@ -15,81 +15,83 @@ describe('oas3-valid-schema-example', () => {
     s.setRules({
       'oas3-valid-schema-example': Object.assign(ruleset.rules['oas3-valid-schema-example'], {
         recommended: true,
-        type: RuleType[ruleset.rules['oas3-valid-schema-example']!.type],
+        type: RuleType[ruleset.rules['oas3-valid-schema-example'].type],
       }),
     });
   });
 
-  test('will pass when simple example is valid', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      components: {
-        schemas: {
-          xoxo: {
-            type: 'string',
-            example: 'doggie',
+  describe.each(['components', 'headers'])('%s', field => {
+    test('will pass when simple example is valid', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        [field]: {
+          schemas: {
+            xoxo: {
+              type: 'string',
+              example: 'doggie',
+            },
           },
         },
-      },
+      });
+      expect(results).toHaveLength(0);
     });
-    expect(results).toHaveLength(0);
-  });
 
-  test('will fail when simple example is invalid', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      components: {
-        schemas: {
-          xoxo: {
-            type: 'string',
-            example: 123,
+    test('will fail when simple example is invalid', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        [field]: {
+          schemas: {
+            xoxo: {
+              type: 'string',
+              example: 123,
+            },
           },
         },
-      },
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-schema-example',
+          message: '`example` property type should be string',
+        }),
+      ]);
     });
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: 'oas3-valid-schema-example',
-        message: '`example` property type should be string',
-      }),
-    ]);
-  });
 
-  test('will pass for valid parents examples which contain invalid child examples', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      info: {
-        version: '1.0.0',
-        title: 'Swagger Petstore',
-      },
-      components: {
-        schemas: {
-          post: {
-            schema: {
-              type: 'object',
-              example: {
-                a: {
-                  b: {
-                    c: 'foo',
-                  },
-                },
-              },
-              properties: {
-                a: {
-                  type: 'object',
-                  example: {
+    test('will fail for valid parents examples which contain invalid child examples', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        info: {
+          version: '1.0.0',
+          title: 'Swagger Petstore',
+        },
+        [field]: {
+          schemas: {
+            post: {
+              schema: {
+                type: 'object',
+                example: {
+                  a: {
                     b: {
                       c: 'foo',
                     },
                   },
-                  properties: {
-                    b: {
-                      type: 'object',
-                      properties: {
-                        c: {
-                          type: 'string',
-                          example: 12345,
+                },
+                properties: {
+                  a: {
+                    type: 'object',
+                    example: {
+                      b: {
+                        c: 'foo',
+                      },
+                    },
+                    properties: {
+                      b: {
+                        type: 'object',
+                        properties: {
+                          c: {
+                            type: 'string',
+                            example: 12345,
+                          },
                         },
                       },
                     },
@@ -99,144 +101,229 @@ describe('oas3-valid-schema-example', () => {
             },
           },
         },
-      },
-    });
+      });
 
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-schema-example',
-        message: '`example` property type should be string',
-        path: [
-          'components',
-          'schemas',
-          'post',
-          'schema',
-          'properties',
-          'a',
-          'properties',
-          'b',
-          'properties',
-          'c',
-          'example',
-        ],
-        range: expect.any(Object),
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-schema-example',
+          message: '`example` property type should be string',
+          path: [
+            field,
+            'schemas',
+            'post',
+            'schema',
+            'properties',
+            'a',
+            'properties',
+            'b',
+            'properties',
+            'c',
+            'example',
+          ],
+          range: expect.any(Object),
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
 
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      components: {
-        schemas: {
-          xoxo: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
+    test('will pass when complex example is used ', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        [field]: {
+          schemas: {
+            xoxo: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
               },
-              height: {
-                type: 'integer',
+              required: ['url'],
+              example: {
+                url: 'images/38.png',
+                width: 100,
+                height: 100,
               },
             },
-            required: ['url'],
-            example: {
-              url: 'images/38.png',
-              width: 100,
-              height: 100,
-            },
           },
         },
-      },
-    });
+      });
 
-    expect(results).toHaveLength(0);
-  });
+      expect(results).toHaveLength(0);
+    });
 
-  test('will fail when complex example is used', async () => {
-    const data = {
-      openapi: '3.0.2',
-      components: {
-        schemas: {
-          xoxo: {
-            type: 'number',
-            example: 4,
-          },
-          abc: {
-            type: 'object',
-            properties: {
-              id: {
-                type: 'integer',
-                format: 'int64',
-              },
-              name: {
-                type: 'string',
+    test('will fail when complex example is used', async () => {
+      const data = {
+        openapi: '3.0.2',
+        components: {
+          schemas: {
+            xoxo: {
+              type: 'number',
+              example: 4,
+            },
+            abc: {
+              type: 'object',
+              properties: {
+                id: {
+                  type: 'integer',
+                  format: 'int64',
+                },
+                name: {
+                  type: 'string',
+                },
+                abc: {
+                  type: 'number',
+                  example: '5',
+                },
               },
-              abc: {
-                type: 'number',
-                example: '5',
+              required: ['name'],
+              example: {
+                name: 'Puma',
+                id: 1,
               },
             },
-            required: ['name'],
-            example: {
-              name: 'Puma',
-              id: 1,
-            },
           },
         },
-      },
-    };
+      };
 
-    const results = await s.run(data);
+      const results = await s.run(data);
 
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-schema-example',
-        message: '`example` property type should be number',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-schema-example',
+          message: '`example` property type should be number',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
 
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      components: {
-        schemas: {
-          xoxo: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
+    test('will error with totally invalid input', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        [field]: {
+          schemas: {
+            xoxo: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
               },
-              width: {
-                type: 'integer',
+              required: ['url'],
+              example: {
+                url2: 'images/38.png',
+                width: 'coffee',
+                height: false,
               },
-              height: {
-                type: 'integer',
+            },
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: 'oas3-valid-schema-example',
+          message: '`example` property should have required property `url`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('does not report example mismatches for unknown AJV formats', async () => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        [field]: {
+          xoxo: {
+            schema: {
+              type: 'object',
+              properties: {
+                ip_address: {
+                  type: 'integer',
+                  format: 'foo',
+                  example: 2886989840,
+                },
               },
             },
-            required: ['url'],
-            example: {
-              url2: 'images/38.png',
-              width: 'coffee',
-              height: false,
+          },
+        },
+      });
+
+      expect(results).toEqual([]);
+    });
+  });
+
+  describe('headers', () => {
+    test.each([
+      ['byte', '1'],
+      ['int32', 2 ** 31],
+      ['int64', 2 ** 63],
+      ['float', 2 ** 128],
+    ])('reports invalid usage of %s format', async (format, example) => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        headers: {
+          xoxo: {
+            schema: {
+              type: 'object',
+              properties: {
+                ip_address: {
+                  type: ['string', 'number'],
+                  format,
+                  example,
+                },
+              },
             },
           },
         },
-      },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: 'oas3-valid-schema-example',
+          message: `\`example\` property should match format \`${format}\``,
+        }),
+      ]);
     });
 
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: 'oas3-valid-schema-example',
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
+    test.each([
+      ['byte', 'MTI3'],
+      ['int32', 2 ** 30],
+      ['int64', 2 ** 40],
+      ['float', 2 ** 64],
+      ['double', 2 ** 1028],
+    ])('does not report valid usage of %s format', async (format, example) => {
+      const results = await s.run({
+        openapi: '3.0.2',
+        headers: {
+          xoxo: {
+            schema: {
+              type: 'object',
+              properties: {
+                ip_address: {
+                  type: ['string', 'number'],
+                  format,
+                  example,
+                },
+              },
+            },
+          },
+        },
+      });
+
+      expect(results).toHaveLength(0);
+    });
   });
 });
diff --git a/src/rulesets/oas/__tests__/templates/_oas-example.ts b/src/rulesets/oas/__tests__/templates/_oas-example.ts
deleted file mode 100644
index e05dbce5..00000000
--- a/src/rulesets/oas/__tests__/templates/_oas-example.ts
+++ /dev/null
@@ -1,278 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../../spectral';
-import { rules } from '../../index.json';
-import { setFunctionContext } from '../../../evaluators';
-import { functions } from '../../../../functions';
-import oasExample from '../../functions/oasExample';
-
-export default (ruleName: string, path: string) => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas3', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      [ruleName]: Object.assign(rules[ruleName], {
-        recommended: true,
-        type: RuleType[rules[ruleName].type],
-      }),
-    });
-  });
-
-  test('will pass when simple example is valid', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-          },
-          example: 'doggie',
-        },
-      },
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when simple example is invalid', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-          },
-          example: 123,
-        },
-      },
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: ruleName,
-        message: '`example` property type should be string',
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-          },
-          example: {
-            url: 'images/38.png',
-            width: 100,
-            height: 100,
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when complex example is used ', async () => {
-    const data = {
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'number',
-          },
-          example: 4,
-        },
-        abc: {
-          schema: {
-            type: 'object',
-            properties: {
-              id: {
-                type: 'integer',
-                format: 'int64',
-              },
-              name: {
-                type: 'string',
-              },
-              abc: {
-                type: 'number',
-                example: '5',
-              },
-            },
-            required: ['name'],
-          },
-          example: {
-            name: 'Puma',
-            id: 1,
-          },
-        },
-      },
-    };
-
-    const results = await s.run(data);
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-              email: {
-                type: 'string',
-                format: 'email',
-              },
-            },
-            required: ['url'],
-          },
-          example: {
-            url2: 'images/38.png',
-            width: 'coffee',
-            height: false,
-            email: 123,
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: ruleName,
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('does not report example mismatches for unknown AJV formats', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-            format: 'foo',
-          },
-          example: 'abc',
-        },
-      },
-    });
-
-    expect(results).toEqual([]);
-  });
-
-  test.each([
-    ['byte', '1'],
-    ['int32', 2 ** 31],
-    ['int64', 2 ** 63],
-    ['float', 2 ** 128],
-  ])('reports invalid usage of %s format', async (format, example) => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: ['string', 'number'],
-            format,
-            properties: {
-              ip_address: {
-                type: 'string',
-              },
-            },
-          },
-          example,
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: ruleName,
-        message: `\`example\` property should match format \`${format}\``,
-      }),
-    ]);
-  });
-
-  test.each([
-    ['byte', 'MTI3'],
-    ['int32', 2 ** 30],
-    ['int64', 2 ** 40],
-    ['float', 2 ** 64],
-    ['double', 2 ** 1028],
-  ])('does not report valid usage of %s format', async (format, example) => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: ['string', 'number'],
-            format,
-            properties: {
-              ip_address: {
-                type: 'string',
-              },
-            },
-          },
-          example,
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when simple example is invalid (examples)', async () => {
-    const results = await s.run({
-      openapi: '3.0.0',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-          },
-          examples: {
-            test1: {
-              value: 123,
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: ruleName,
-        message: '`value` property type should be string',
-      }),
-    ]);
-  });
-};
diff --git a/src/rulesets/oas/__tests__/templates/_schema-example.ts b/src/rulesets/oas/__tests__/templates/_schema-example.ts
deleted file mode 100644
index 0e7da1ca..00000000
--- a/src/rulesets/oas/__tests__/templates/_schema-example.ts
+++ /dev/null
@@ -1,311 +0,0 @@
-import { DiagnosticSeverity } from '@stoplight/types';
-import { RuleType, Spectral } from '../../../../spectral';
-import { rules } from '../../index.json';
-import { setFunctionContext } from '../../../evaluators';
-import { functions } from '../../../../functions';
-import oasExample from '../../functions/oasExample';
-
-export default (ruleName: string, path: string) => {
-  let s: Spectral;
-
-  beforeEach(() => {
-    s = new Spectral();
-    s.registerFormat('oas3', () => true);
-    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
-    s.setRules({
-      [ruleName]: Object.assign(rules[ruleName], {
-        recommended: true,
-        type: RuleType[rules[ruleName].type],
-      }),
-    });
-  });
-
-  test('will pass when simple example is valid', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-            example: 'doggie',
-          },
-        },
-      },
-    });
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when simple example is invalid', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'string',
-            example: 123,
-          },
-        },
-      },
-    });
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: ruleName,
-        message: '`example` property type should be string',
-      }),
-    ]);
-  });
-
-  test('will pass for valid parents examples which contain invalid child examples', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: [
-          {
-            schema: {
-              type: 'object',
-              example: {
-                a: {
-                  b: {
-                    c: 'foo',
-                  },
-                },
-              },
-              properties: {
-                a: {
-                  type: 'object',
-                  example: {
-                    b: {
-                      c: 'foo',
-                    },
-                  },
-                  properties: {
-                    b: {
-                      type: 'object',
-                      properties: {
-                        c: {
-                          type: 'string',
-                          example: 12345,
-                        },
-                      },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        ],
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: ruleName,
-        message: '`example` property type should be string',
-        path: [path, 'xoxo', '0', 'schema', 'properties', 'a', 'properties', 'b', 'properties', 'c', 'example'],
-        range: expect.any(Object),
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will pass when complex example is used ', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url: 'images/38.png',
-              width: 100,
-              height: 100,
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-
-  test('will fail when complex example is used ', async () => {
-    const data = {
-      openapi: '3.0.2',
-      [path]: {
-        Heh: {
-          schema: {
-            type: 'number',
-            example: 4,
-          },
-        },
-        Abc: {
-          schema: {
-            type: 'object',
-            properties: {
-              id: {
-                type: 'integer',
-                format: 'int64',
-              },
-              name: {
-                type: 'string',
-              },
-              abc: {
-                type: 'number',
-                example: '5',
-              },
-            },
-            required: ['name'],
-            example: {
-              name: 'Puma',
-              id: 1,
-            },
-          },
-        },
-      },
-    };
-
-    const results = await s.run(data);
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: ruleName,
-        message: '`example` property type should be number',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('will error with totally invalid input', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              url: {
-                type: 'string',
-              },
-              width: {
-                type: 'integer',
-              },
-              height: {
-                type: 'integer',
-              },
-            },
-            required: ['url'],
-            example: {
-              url2: 'images/38.png',
-              width: 'coffee',
-              height: false,
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        code: ruleName,
-        message: '`example` property should have required property `url`',
-        severity: DiagnosticSeverity.Error,
-      }),
-    ]);
-  });
-
-  test('does not report example mismatches for unknown AJV formats', async () => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              ip_address: {
-                type: 'integer',
-                format: 'foo',
-                example: 2886989840,
-              },
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([]);
-  });
-
-  test.each([
-    ['byte', '1'],
-    ['int32', 2 ** 31],
-    ['int64', 2 ** 63],
-    ['float', 2 ** 128],
-  ])('reports invalid usage of %s format', async (format, example) => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              ip_address: {
-                type: ['string', 'number'],
-                format,
-                example,
-              },
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toEqual([
-      expect.objectContaining({
-        severity: DiagnosticSeverity.Error,
-        code: ruleName,
-        message: `\`example\` property should match format \`${format}\``,
-      }),
-    ]);
-  });
-
-  test.each([
-    ['byte', 'MTI3'],
-    ['int32', 2 ** 30],
-    ['int64', 2 ** 40],
-    ['float', 2 ** 64],
-    ['double', 2 ** 1028],
-  ])('does not report valid usage of %s format', async (format, example) => {
-    const results = await s.run({
-      openapi: '3.0.2',
-      [path]: {
-        xoxo: {
-          schema: {
-            type: 'object',
-            properties: {
-              ip_address: {
-                type: ['string', 'number'],
-                format,
-                example,
-              },
-            },
-          },
-        },
-      },
-    });
-
-    expect(results).toHaveLength(0);
-  });
-};
diff --git a/src/rulesets/oas/__tests__/valid-example.test.ts b/src/rulesets/oas/__tests__/valid-example.test.ts
new file mode 100644
index 00000000..87058fa0
--- /dev/null
+++ b/src/rulesets/oas/__tests__/valid-example.test.ts
@@ -0,0 +1,304 @@
+import { DiagnosticSeverity } from '@stoplight/types';
+import { RuleType, Spectral } from '../../../spectral';
+import { setFunctionContext } from '../../evaluators';
+import { functions } from '../../../functions';
+import oasExample from '../functions/oasExample';
+import * as ruleset from '../index.json';
+
+describe.each(['oas2', 'oas3'])('%s', spec => {
+  let s: Spectral;
+
+  beforeEach(() => {
+    s = new Spectral();
+    s.registerFormat(spec, () => true);
+    s.setFunctions({ oasExample: setFunctionContext({ functions }, oasExample) });
+    s.setRules({
+      'oas2-valid-schema-example': Object.assign(ruleset.rules['oas2-valid-schema-example'], {
+        recommended: true,
+        type: RuleType[ruleset.rules['oas2-valid-schema-example'].type],
+      }),
+      'oas3-valid-schema-example': Object.assign(ruleset.rules['oas3-valid-schema-example'], {
+        recommended: true,
+        type: RuleType[ruleset.rules['oas3-valid-schema-example'].type],
+      }),
+    });
+  });
+
+  describe('parameters', () => {
+    test('will pass when simple example is valid', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'string',
+              example: 'doggie',
+            },
+          },
+        ],
+      });
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail for valid parents examples which contain invalid child examples', async () => {
+      const results = await s.run({
+        info: {
+          version: '1.0.0',
+        },
+        paths: {
+          '/pet': {
+            post: {
+              parameters: [
+                {
+                  in: 'body',
+                  name: 'body',
+                  required: true,
+                  schema: {
+                    type: 'object',
+                    example: {
+                      a: {
+                        b: {
+                          c: 'foo',
+                        },
+                      },
+                    },
+                    properties: {
+                      a: {
+                        type: 'object',
+                        example: {
+                          b: {
+                            c: 'foo',
+                          },
+                        },
+                        properties: {
+                          b: {
+                            type: 'object',
+                            properties: {
+                              c: {
+                                type: 'string',
+                                example: 12345,
+                              },
+                            },
+                          },
+                        },
+                      },
+                    },
+                  },
+                },
+              ],
+              responses: {
+                '200': {
+                  description: 'OK',
+                },
+              },
+            },
+          },
+        },
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: `${spec}-valid-schema-example`,
+          message: '`example` property type should be string',
+          path: [
+            'paths',
+            '/pet',
+            'post',
+            'parameters',
+            '0',
+            'schema',
+            'properties',
+            'a',
+            'properties',
+            'b',
+            'properties',
+            'c',
+            'example',
+          ],
+          range: expect.any(Object),
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will not fail if an actual property is called example', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            in: 'body',
+            type: 'object',
+            properties: {
+              example: {
+                description: 'an actual field called example...',
+                type: 'string',
+              },
+            },
+            example: {
+              example: 'what is gonna happen',
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will not fail if an actual property is called example and there is also type/format property', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            type: 'object',
+            properties: {
+              example: {
+                type: 'string',
+                example: 'abc',
+              },
+              type: {
+                type: 'number',
+                example: 123,
+              },
+              format: 'plain text',
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when simple example is invalid', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'string',
+              example: 123,
+            },
+          },
+        ],
+      });
+      expect(results).toEqual([
+        expect.objectContaining({
+          severity: DiagnosticSeverity.Error,
+          code: `${spec}-valid-schema-example`,
+          message: '`example` property type should be string',
+        }),
+      ]);
+    });
+
+    test('will pass when complex example is used ', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+              example: {
+                url: 'images/38.png',
+                width: 100,
+                height: 100,
+              },
+            },
+          },
+        ],
+      });
+
+      expect(results).toHaveLength(0);
+    });
+
+    test('will fail when complex example is used', async () => {
+      const data = {
+        parameters: [
+          {
+            Heh: {
+              schema: {
+                type: 'number',
+                example: 4,
+              },
+            },
+            Abc: {
+              schema: {
+                type: 'object',
+                properties: {
+                  id: {
+                    type: 'integer',
+                    format: 'int64',
+                  },
+                  name: {
+                    type: 'string',
+                  },
+                  abc: {
+                    type: 'number',
+                    example: '5',
+                  },
+                },
+                required: ['name'],
+                example: {
+                  name: 'Puma',
+                  id: 1,
+                },
+              },
+            },
+          },
+        ],
+      };
+
+      const results = await s.run(data);
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: `${spec}-valid-schema-example`,
+          message: '`example` property type should be number',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+
+    test('will error with totally invalid input', async () => {
+      const results = await s.run({
+        parameters: [
+          {
+            schema: {
+              type: 'object',
+              properties: {
+                url: {
+                  type: 'string',
+                },
+                width: {
+                  type: 'integer',
+                },
+                height: {
+                  type: 'integer',
+                },
+              },
+              required: ['url'],
+              example: {
+                url2: 'images/38.png',
+                width: 'coffee',
+                height: false,
+              },
+            },
+          },
+        ],
+      });
+
+      expect(results).toEqual([
+        expect.objectContaining({
+          code: `${spec}-valid-schema-example`,
+          message: '`example` property should have required property `url`',
+          severity: DiagnosticSeverity.Error,
+        }),
+      ]);
+    });
+  });
+});
diff --git a/test-harness/scenarios/enabled-rules-amount.oas3.scenario b/test-harness/scenarios/enabled-rules-amount.oas3.scenario
index 9cbb763e..88231364 100644
--- a/test-harness/scenarios/enabled-rules-amount.oas3.scenario
+++ b/test-harness/scenarios/enabled-rules-amount.oas3.scenario
@@ -24,7 +24,7 @@ components:
 ====command====
 {bin} lint {document} --ruleset ./rulesets/parameter-description.oas3.yaml -v
 ====stdout====
-Found 54 rules (1 enabled)
+Found 48 rules (1 enabled)
 Linting {document}
 OpenAPI 3.x detected
 
diff --git a/test-harness/scenarios/examples.oas2.scenario b/test-harness/scenarios/examples.oas2.scenario
index d57fd478..906df83b 100644
--- a/test-harness/scenarios/examples.oas2.scenario
+++ b/test-harness/scenarios/examples.oas2.scenario
@@ -263,13 +263,13 @@ definitions:
 OpenAPI 2.0 (Swagger) detected
 
 {document}
-  83:26    error  oas2-valid-response-schema-example  `completed` property type should be boolean
-  91:26    error  oas2-valid-response-schema-example  `example` property type should be boolean
-  95:26    error  oas2-valid-response-schema-example  `example` property should match format `date-time`
-  99:26    error  oas2-valid-response-schema-example  `example` property should match format `url`
- 106:11  warning  operation-tag-defined               Operation tags should be defined in global tags.
- 120:22    error  oas2-valid-parameter-example        `x-example` property should be equal to one of the allowed values: foo, bar
- 177:30    error  oas2-valid-response-example         `application/json` property should have required property `name`
- 194:30    error  oas2-valid-response-example         `application/json` property should have required property `user`
+  83:26    error  oas2-valid-schema-example  `completed` property type should be boolean
+  91:26    error  oas2-valid-schema-example  `example` property type should be boolean
+  95:26    error  oas2-valid-schema-example  `example` property should match format `date-time`
+  99:26    error  oas2-valid-schema-example  `example` property should match format `url`
+ 106:11  warning  operation-tag-defined      Operation tags should be defined in global tags.
+ 120:22    error  oas2-valid-schema-example  `x-example` property should be equal to one of the allowed values: foo, bar
+ 177:30    error  oas2-valid-media-example   `application/json` property should have required property `name`
+ 194:30    error  oas2-valid-media-example   `application/json` property should have required property `user`
 
 ✖ 8 problems (7 errors, 1 warning, 0 infos, 0 hints)
diff --git a/test-harness/scenarios/examples.oas3.scenario b/test-harness/scenarios/examples.oas3.scenario
index b50dcf1a..f6363960 100644
--- a/test-harness/scenarios/examples.oas3.scenario
+++ b/test-harness/scenarios/examples.oas3.scenario
@@ -352,15 +352,15 @@ components:
 OpenAPI 3.x detected
 
 {document}
- 126:25  error  oas3-valid-schema-example            `example` property should have required property `name`
- 138:30  error  oas3-valid-schema-example            `example` property type should be boolean
- 142:30  error  oas3-valid-schema-example            `example` property should match format `date-time`
- 146:30  error  oas3-valid-schema-example            `example` property should match format `url`
- 169:20  error  oas3-valid-oas-parameter-example     `example` property should be equal to one of the allowed values: foo, bar
- 185:22  error  oas3-valid-parameter-schema-example  `example` property should be equal to one of the allowed values: foo, bar
- 197:22  error  oas3-valid-oas-parameter-example     `value` property type should be string
- 199:21  error  oas3-valid-oas-parameter-example     `value` property type should be string
- 262:25  error  oas3-valid-oas-content-example       `value` property should have required property `id`
- 282:25  error  oas3-valid-oas-content-example       `value` property should have required property `user`
+ 126:25  error  oas3-valid-schema-example  `example` property should have required property `name`
+ 138:30  error  oas3-valid-schema-example  `example` property type should be boolean
+ 142:30  error  oas3-valid-schema-example  `example` property should match format `date-time`
+ 146:30  error  oas3-valid-schema-example  `example` property should match format `url`
+ 169:20  error  oas3-valid-media-example   `example` property should be equal to one of the allowed values: foo, bar
+ 185:22  error  oas3-valid-schema-example  `example` property should be equal to one of the allowed values: foo, bar
+ 197:22  error  oas3-valid-media-example   `value` property type should be string
+ 199:21  error  oas3-valid-media-example   `value` property type should be string
+ 262:25  error  oas3-valid-media-example   `value` property should have required property `id`
+ 282:25  error  oas3-valid-media-example   `value` property should have required property `user`
 
 ✖ 10 problems (10 errors, 0 warnings, 0 infos, 0 hints)
diff --git a/test-harness/scenarios/valid-response-examples.oas2.scenario b/test-harness/scenarios/oas2-valid-media-example.oas2.scenario
similarity index 79%
rename from test-harness/scenarios/valid-response-examples.oas2.scenario
rename to test-harness/scenarios/oas2-valid-media-example.oas2.scenario
index f15793ad..1be5a4d2 100644
--- a/test-harness/scenarios/valid-response-examples.oas2.scenario
+++ b/test-harness/scenarios/oas2-valid-media-example.oas2.scenario
@@ -31,14 +31,14 @@ paths:
 ====asset:ruleset====
 extends: [[spectral:oas, off]]
 rules:
-  oas2-valid-response-example: error
+  oas2-valid-media-example: error
 ====command====
 {bin} lint {document} --ruleset {asset:ruleset}
 ====stdout====
 OpenAPI 2.0 (Swagger) detected
 
 {document}
- 11:31  error  oas2-valid-response-example  `application/json` property type should be boolean
- 26:32  error  oas2-valid-response-example  `application/yaml` property should have required property `user`
+ 11:31  error  oas2-valid-media-example  `application/json` property type should be boolean
+ 26:32  error  oas2-valid-media-example  `application/yaml` property should have required property `user`
 
 ✖ 2 problems (2 errors, 0 warnings, 0 infos, 0 hints)