Repository: lukeautry/tsoa (ts)

Issue:
Single literal type does not work correctly
```
interface WorksCorrectly {
  myLiteral: 'hello' | 'world';
}

interface DoesNotWork {
  myLiteral: 'hello';
}
```

I believe that this should produce an enum that allows a single item.

A workaround is to declare it as a typescript enum, or a string literal with two redundant values
```
enum SingleValueEnum {
  HELLO = 'hello',
}

interface WorkAround {
  myLiteral: SingleValueEnum;
}

interface WorkAroundUglier {
  myLiteral: 'hello' | 'hello';
}
```

Pull request:
Single literal type
### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/lukeautry/tsoa/tree/master/docs/CONTRIBUTING.md) document?
* [x] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/lukeautry/tsoa/pulls) for the same update/change?
* [x] Have you written unit tests?
* [x] Have you written unit tests that cover the negative cases (i.e.: if bad data is submitted, does the library respond properly)?
* [x] This PR is associated with an existing issue?

**Closing issues**

Closes #320 

### If this is a new feature submission:

* [x] Has the issue had a maintainer respond to the issue and clarify that the feature is something that aligns with the [goals](https://github.com/lukeautry/tsoa#goal) and [philosophy](https://github.com/lukeautry/tsoa#philosophy) of the project?


Patch:
diff --git a/README.MD b/README.MD
index df92293e..8035464e 100644
--- a/README.MD
+++ b/README.MD
@@ -800,35 +800,6 @@ public async find(): Promise<any> {
 }
 ```
 
-### Hidden
-
-Excludes this endpoint from the generated swagger document.
-
-```ts
-  @Get()
-  @Hidden()
-  public async find(): Promise<any> {
-
-  }
-```
-
-It can also be set at the controller level to exclude all of its endpoints from the swagger document.
-
-```ts
-@Hidden()
-export class HiddenController {
-  @Get()
-  public async find(): Promise<any> {
-
-  }
-
-  @Post()
-  public async create(): Promise<any> {
-
-  }
-}
-```
-
 ## Command Line Interface
 
 For information on the configuration object (tsoa.json), check out the following:
diff --git a/package.json b/package.json
index 11ff3080..f7e13a21 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "tsoa",
   "description": "Build swagger-compliant REST APIs using TypeScript and Node",
-  "version": "2.5.6",
+  "version": "2.5.5",
   "main": "./dist/index.js",
   "typings": "./dist/index.d.ts",
   "keywords": [
diff --git a/src/metadataGeneration/controllerGenerator.ts b/src/metadataGeneration/controllerGenerator.ts
index bb2793fd..ad2d3722 100644
--- a/src/metadataGeneration/controllerGenerator.ts
+++ b/src/metadataGeneration/controllerGenerator.ts
@@ -10,13 +10,11 @@ export class ControllerGenerator {
   private readonly path?: string;
   private readonly tags?: string[];
   private readonly security?: Tsoa.Security[];
-  private readonly isHidden?: boolean;
 
   constructor(private readonly node: ts.ClassDeclaration, private readonly current: MetadataGenerator) {
     this.path = this.getPath();
     this.tags = this.getTags();
     this.security = this.getSecurity();
-    this.isHidden = this.getIsHidden();
   }
 
   public IsValid() {
@@ -44,7 +42,7 @@ export class ControllerGenerator {
   private buildMethods() {
     return this.node.members
       .filter(m => m.kind === ts.SyntaxKind.MethodDeclaration)
-      .map((m: ts.MethodDeclaration) => new MethodGenerator(m, this.current, this.tags, this.security, this.isHidden))
+      .map((m: ts.MethodDeclaration) => new MethodGenerator(m, this.current, this.tags, this.security))
       .filter(generator => generator.IsValid())
       .map(generator => generator.Generate());
   }
@@ -87,16 +85,4 @@ export class ControllerGenerator {
 
     return getSecurities(securityDecorators);
   }
-
-  private getIsHidden(): boolean {
-    const hiddenDecorators = getDecorators(this.node, identifier => identifier.text === 'Hidden');
-    if (!hiddenDecorators || !hiddenDecorators.length) {
-      return false;
-    }
-    if (hiddenDecorators.length > 1) {
-      throw new GenerateMetadataError(`Only one Hidden decorator allowed in '${this.node.name!.text}' class.`);
-    }
-
-    return true;
-  }
 }
diff --git a/src/metadataGeneration/methodGenerator.ts b/src/metadataGeneration/methodGenerator.ts
index 6f47ba18..1112b2ff 100644
--- a/src/metadataGeneration/methodGenerator.ts
+++ b/src/metadataGeneration/methodGenerator.ts
@@ -13,13 +13,7 @@ export class MethodGenerator {
   private method: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head';
   private path: string;
 
-  constructor(
-    private readonly node: ts.MethodDeclaration,
-    private readonly current: MetadataGenerator,
-    private readonly parentTags?: string[],
-    private readonly parentSecurity?: Tsoa.Security[],
-    private readonly isParentHidden?: boolean,
-  ) {
+  constructor(private readonly node: ts.MethodDeclaration, private readonly current: MetadataGenerator, private readonly parentTags?: string[], private readonly parentSecurity?: Tsoa.Security[]) {
     this.processMethodDecorators();
   }
 
@@ -257,13 +251,8 @@ export class MethodGenerator {
   private getIsHidden() {
     const hiddenDecorators = this.getDecoratorsByIdentifier(this.node, 'Hidden');
     if (!hiddenDecorators || !hiddenDecorators.length) {
-      return !!this.isParentHidden;
-    }
-
-    if (this.isParentHidden) {
-      throw new GenerateMetadataError(`Hidden decorator cannot be set on '${this.getCurrentLocation()}' it is already defined on the controller`);
+      return false;
     }
-
     if (hiddenDecorators.length > 1) {
       throw new GenerateMetadataError(`Only one Hidden decorator allowed in '${this.getCurrentLocation}' method.`);
     }
diff --git a/src/metadataGeneration/typeResolver.ts b/src/metadataGeneration/typeResolver.ts
index 87b5d041..131f59e6 100644
--- a/src/metadataGeneration/typeResolver.ts
+++ b/src/metadataGeneration/typeResolver.ts
@@ -54,16 +54,7 @@ export class TypeResolver {
       if (supportType) {
         const enumMetaType: Tsoa.EnumType = {
           dataType: 'enum',
-          enums: (this.typeNode.types as ts.NodeArray<ts.LiteralTypeNode>).map(type => {
-            switch (type.literal.kind) {
-              case ts.SyntaxKind.TrueKeyword:
-                return 'true';
-              case ts.SyntaxKind.FalseKeyword:
-                return 'false';
-              default:
-                return String((type.literal as ts.LiteralExpression).text);
-            }
-          }),
+          enums: (this.typeNode.types as ts.NodeArray<ts.LiteralTypeNode>).map(type => this.resolveLiteralValue(type)),
         };
         return enumMetaType;
       } else {
@@ -99,6 +90,14 @@ export class TypeResolver {
       return literallyAny;
     }
 
+    if (ts.isLiteralTypeNode(this.typeNode)) {
+      const enumType: Tsoa.EnumType = {
+        dataType: 'enum',
+        enums: [this.resolveLiteralValue(this.typeNode)],
+      };
+      return enumType;
+    }
+
     if (ts.isTypeLiteralNode(this.typeNode)) {
       const properties = this.typeNode.members
         .filter(member => ts.isPropertySignature(member))
@@ -214,6 +213,31 @@ export class TypeResolver {
     return enumOrReferenceType;
   }
 
+  private resolveLiteralValue(typeNode: ts.LiteralTypeNode): string {
+    let value: boolean | number | string;
+    switch (typeNode.literal.kind) {
+      case ts.SyntaxKind.TrueKeyword:
+        value = 'true';
+        break;
+      case ts.SyntaxKind.FalseKeyword:
+        value = 'false';
+        break;
+      case ts.SyntaxKind.StringLiteral:
+        value = typeNode.literal.text;
+        break;
+      case ts.SyntaxKind.NumericLiteral:
+        value = typeNode.literal.text;
+        break;
+      default:
+        if (typeNode.literal.hasOwnProperty('text')) {
+          value = (typeNode.literal as ts.LiteralExpression).text;
+        } else {
+          throw new GenerateMetadataError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`);
+        }
+    }
+    return value;
+  }
+
   private checkRefNameForBadCharacters(ref: Tsoa.ReferenceType) {
     // We do a hard assert in the test mode so we can catch bad ref names (https://github.com/lukeautry/tsoa/issues/398).
     //   The goal is to avoid producing these names before the code is ever merged to master (via extensive test coverage)


Test patch:
diff --git a/tests/fixtures/controllers/hiddenController.ts b/tests/fixtures/controllers/hiddenController.ts
deleted file mode 100644
index 880d1ecc..00000000
--- a/tests/fixtures/controllers/hiddenController.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Controller, Get, Hidden, Post, Route } from '../../../src';
-import { ModelService } from '../services/modelService';
-import { TestModel } from '../testModel';
-
-@Route('Controller')
-@Hidden()
-export class HiddenMethodController extends Controller {
-  @Get('hiddenGetMethod')
-  public async hiddenGetMethod(): Promise<TestModel> {
-    return Promise.resolve(new ModelService().getModel());
-  }
-  @Post('hiddenPostMethod')
-  public async hiddenPostMethod(): Promise<TestModel> {
-    return Promise.resolve(new ModelService().getModel());
-  }
-}
diff --git a/tests/fixtures/testModel.ts b/tests/fixtures/testModel.ts
index 2135f8ea..a2e8493c 100644
--- a/tests/fixtures/testModel.ts
+++ b/tests/fixtures/testModel.ts
@@ -53,6 +53,7 @@ export interface TestModel extends Model {
   strLiteralVal: StrLiteral;
   strLiteralArr: StrLiteral[];
   unionPrimetiveType?: 'String' | 1 | 20.0 | true | false;
+  singleFloatLiteralType?: 3.1415;
   dateValue?: Date;
   optionalString?: string;
   anyType?: any;
@@ -296,6 +297,7 @@ export class ValidateModel {
   public intersection?: TypeAliasModel1 & TypeAliasModel2;
   public intersectionNoAdditional?: TypeAliasModel1 & TypeAliasModel2;
   public mixedUnion?: string | TypeAliasModel1;
+  public singleBooleanEnum?: true;
 
   public nestedObject: {
     /**
diff --git a/tests/integration/dynamic-controllers-express-server.spec.ts b/tests/integration/dynamic-controllers-express-server.spec.ts
index 844c88b4..929f9b62 100644
--- a/tests/integration/dynamic-controllers-express-server.spec.ts
+++ b/tests/integration/dynamic-controllers-express-server.spec.ts
@@ -500,6 +500,7 @@ describe('Express Server', () => {
       bodyModel.model = { value1: 'abcdef' };
       bodyModel.mixedUnion = { value1: '' };
       bodyModel.intersection = { value1: 'one', value2: 'two' };
+      bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: 1.2,
@@ -553,6 +554,7 @@ describe('Express Server', () => {
           expect(body.model).to.deep.equal(bodyModel.model);
           expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
           expect(body.intersection).to.deep.equal(bodyModel.intersection);
+          expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
           expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
           expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
@@ -603,6 +605,7 @@ describe('Express Server', () => {
       bodyModel.model = 1 as any;
       bodyModel.mixedUnion = 123 as any;
       bodyModel.intersection = { value1: 'one' } as any;
+      bodyModel.singleBooleanEnum = ('false' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: '120a' as any,
@@ -674,7 +677,7 @@ describe('Express Server', () => {
               '{"body.mixedUnion":{"message":"invalid object","value":123}}]',
           );
           expect(body.fields['body.intersection'].message).to.equal('Could not match the intersection against every type. Issues: [{"body.value2":{"message":"\'value2\' is required"}}]');
-
+          expect(body.fields['body.singleBooleanEnum'].message).to.equal("should be one of the following; ['true']");
           expect(body.fields['body.nestedObject.floatValue'].message).to.equal('Invalid float error message.');
           expect(body.fields['body.nestedObject.floatValue'].value).to.equal(bodyModel.floatValue);
           expect(body.fields['body.nestedObject.doubleValue'].message).to.equal('Invalid double error message.');
diff --git a/tests/integration/express-server.spec.ts b/tests/integration/express-server.spec.ts
index 1d1de360..954e9d78 100644
--- a/tests/integration/express-server.spec.ts
+++ b/tests/integration/express-server.spec.ts
@@ -520,6 +520,7 @@ describe('Express Server', () => {
       bodyModel.model = { value1: 'abcdef' };
       bodyModel.mixedUnion = { value1: '' };
       bodyModel.intersection = { value1: 'one', value2: 'two' };
+      bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: 1.2,
@@ -573,6 +574,7 @@ describe('Express Server', () => {
           expect(body.model).to.deep.equal(bodyModel.model);
           expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
           expect(body.intersection).to.deep.equal(bodyModel.intersection);
+          expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
           expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
           expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
@@ -623,6 +625,7 @@ describe('Express Server', () => {
       bodyModel.model = 1 as any;
       bodyModel.mixedUnion = 123 as any;
       bodyModel.intersection = { value1: 'one' } as any;
+      bodyModel.singleBooleanEnum = ('false' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: '120a' as any,
@@ -694,6 +697,7 @@ describe('Express Server', () => {
               '{"body.mixedUnion":{"message":"invalid object","value":123}}]',
           );
           expect(body.fields['body.intersection'].message).to.equal('Could not match the intersection against every type. Issues: [{"body.value2":{"message":"\'value2\' is required"}}]');
+          expect(body.fields['body.singleBooleanEnum'].message).to.equal("should be one of the following; ['true']");
 
           expect(body.fields['body.nestedObject.floatValue'].message).to.equal('Invalid float error message.');
           expect(body.fields['body.nestedObject.floatValue'].value).to.equal(bodyModel.floatValue);
diff --git a/tests/integration/hapi-server.spec.ts b/tests/integration/hapi-server.spec.ts
index 052edb0e..facc730f 100644
--- a/tests/integration/hapi-server.spec.ts
+++ b/tests/integration/hapi-server.spec.ts
@@ -473,6 +473,7 @@ describe('Hapi Server', () => {
       bodyModel.model = { value1: 'abcdef' };
       bodyModel.mixedUnion = { value1: '' };
       bodyModel.intersection = { value1: 'one', value2: 'two' };
+      bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: 1.2,
@@ -526,6 +527,7 @@ describe('Hapi Server', () => {
           expect(body.model).to.deep.equal(bodyModel.model);
           expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
           expect(body.intersection).to.deep.equal(bodyModel.intersection);
+          expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
           expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
           expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
@@ -576,6 +578,7 @@ describe('Hapi Server', () => {
       bodyModel.model = 1 as any;
       bodyModel.mixedUnion = 123 as any;
       bodyModel.intersection = { value1: 'one' } as any;
+      bodyModel.singleBooleanEnum = ('false' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: '120a' as any,
@@ -647,6 +650,7 @@ describe('Hapi Server', () => {
               '{"body.mixedUnion":{"message":"invalid object","value":123}}]',
           );
           expect(body.fields['body.intersection'].message).to.equal('Could not match the intersection against every type. Issues: [{"body.value2":{"message":"\'value2\' is required"}}]');
+          expect(body.fields['body.singleBooleanEnum'].message).to.equal("should be one of the following; ['true']");
 
           expect(body.fields['body.nestedObject.floatValue'].message).to.equal('Invalid float error message.');
           expect(body.fields['body.nestedObject.floatValue'].value).to.equal(bodyModel.floatValue);
diff --git a/tests/integration/koa-server-no-additional-allowed.spec.ts b/tests/integration/koa-server-no-additional-allowed.spec.ts
index 37df8191..281cc104 100644
--- a/tests/integration/koa-server-no-additional-allowed.spec.ts
+++ b/tests/integration/koa-server-no-additional-allowed.spec.ts
@@ -195,6 +195,7 @@ describe('Koa Server (with noImplicitAdditionalProperties turned on)', () => {
       bodyModel.model = { value1: 'abcdef' };
       bodyModel.mixedUnion = { value1: '' };
       bodyModel.intersection = { value1: 'one', value2: 'two' };
+      bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: 1.2,
@@ -248,6 +249,7 @@ describe('Koa Server (with noImplicitAdditionalProperties turned on)', () => {
           expect(body.model).to.deep.equal(bodyModel.model);
           expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
           expect(body.intersection).to.deep.equal(bodyModel.intersection);
+          expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
           expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
           expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
diff --git a/tests/integration/koa-server.spec.ts b/tests/integration/koa-server.spec.ts
index 86b67a5c..f2d441ba 100644
--- a/tests/integration/koa-server.spec.ts
+++ b/tests/integration/koa-server.spec.ts
@@ -451,6 +451,7 @@ describe('Koa Server', () => {
       bodyModel.model = { value1: 'abcdef' };
       bodyModel.mixedUnion = { value1: '' };
       bodyModel.intersection = { value1: 'one', value2: 'two' };
+      bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: 1.2,
@@ -504,6 +505,7 @@ describe('Koa Server', () => {
           expect(body.model).to.deep.equal(bodyModel.model);
           expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
           expect(body.intersection).to.deep.equal(bodyModel.intersection);
+          expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
           expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
           expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
@@ -554,6 +556,7 @@ describe('Koa Server', () => {
       bodyModel.model = 1 as any;
       bodyModel.mixedUnion = 123 as any;
       bodyModel.intersection = { value1: 'one' } as any;
+      bodyModel.singleBooleanEnum = ('false' as unknown) as true;
 
       bodyModel.nestedObject = {
         floatValue: '120a' as any,
@@ -625,6 +628,7 @@ describe('Koa Server', () => {
               '{"body.mixedUnion":{"message":"invalid object","value":123}}]',
           );
           expect(body.fields['body.intersection'].message).to.equal('Could not match the intersection against every type. Issues: [{"body.value2":{"message":"\'value2\' is required"}}]');
+          expect(body.fields['body.singleBooleanEnum'].message).to.equal("should be one of the following; ['true']");
 
           expect(body.fields['body.nestedObject.floatValue'].message).to.equal('Invalid float error message.');
           expect(body.fields['body.nestedObject.floatValue'].value).to.equal(bodyModel.floatValue);
diff --git a/tests/integration/openapi3-express.spec.ts b/tests/integration/openapi3-express.spec.ts
index c0b9b63f..8a51612f 100644
--- a/tests/integration/openapi3-express.spec.ts
+++ b/tests/integration/openapi3-express.spec.ts
@@ -30,6 +30,7 @@ describe('OpenAPI3 Express Server', () => {
     bodyModel.model = { value1: 'abcdef' };
     bodyModel.mixedUnion = { value1: '' };
     bodyModel.intersection = { value1: 'one', value2: 'two' };
+    bodyModel.singleBooleanEnum = ('true' as unknown) as true;
 
     bodyModel.nestedObject = {
       floatValue: 1.2,
@@ -83,6 +84,7 @@ describe('OpenAPI3 Express Server', () => {
         expect(body.model).to.deep.equal(bodyModel.model);
         expect(body.mixedUnion).to.deep.equal(bodyModel.mixedUnion);
         expect(body.intersection).to.deep.equal(bodyModel.intersection);
+        expect(body.singleBooleanEnum).to.deep.equal(bodyModel.singleBooleanEnum);
 
         expect(body.nestedObject.floatValue).to.equal(bodyModel.nestedObject.floatValue);
         expect(body.nestedObject.doubleValue).to.equal(bodyModel.nestedObject.doubleValue);
@@ -134,7 +136,7 @@ describe('OpenAPI3 Express Server', () => {
     bodyModel.intersectionNoAdditional = { value1: '', value2: '', value3: 123, value4: 123 } as any;
     bodyModel.model = 1 as any;
     bodyModel.mixedUnion = 123 as any;
-    bodyModel.intersection = { value1: 'one' } as any;
+    bodyModel.singleBooleanEnum = ('false' as unknown) as true;
 
     bodyModel.nestedObject = {
       floatValue: '120a' as any,
@@ -208,6 +210,7 @@ describe('OpenAPI3 Express Server', () => {
             '{"body.mixedUnion":{"message":"invalid object","value":123}}]',
         );
         expect(body.fields['body.intersection'].message).to.equal('Could not match the intersection against every type. Issues: [{"body.value2":{"message":"\'value2\' is required"}}]');
+        expect(body.fields['body.singleBooleanEnum'].message).to.equal("should be one of the following; ['true']");
 
         expect(body.fields['body.nestedObject.floatValue'].message).to.equal('Invalid float error message.');
         expect(body.fields['body.nestedObject.floatValue'].value).to.equal(bodyModel.floatValue);
diff --git a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
index b62ca5b1..fe02effd 100644
--- a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
+++ b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
@@ -358,6 +358,15 @@ describe('Definition generation', () => {
             expect(propertySchema.enum).to.include('true', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('false', `for property ${propertyName}.enum`);
           },
+          singleFloatLiteralType: (propertyName, propertySchema) => {
+            expect(propertySchema.type).to.eq('string', `for property ${propertyName}.type`);
+            expect(propertySchema['x-nullable']).to.eq(true, `for property ${propertyName}[x-nullable]`);
+            if (!propertySchema.enum) {
+              throw new Error(`There was no 'enum' property on ${propertyName}.`);
+            }
+            expect(propertySchema.enum).to.have.length(1, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.include('3.1415', `for property ${propertyName}.enum`);
+          },
           dateValue: (propertyName, propertySchema) => {
             expect(propertySchema.type).to.eq('string', `for property ${propertyName}.type`);
             expect(propertySchema['x-nullable']).to.eq(true, `for property ${propertyName}[x-nullable]`);
diff --git a/tests/unit/swagger/definitionsGeneration/metadata.spec.ts b/tests/unit/swagger/definitionsGeneration/metadata.spec.ts
index 3043b7b3..dd9d083c 100644
--- a/tests/unit/swagger/definitionsGeneration/metadata.spec.ts
+++ b/tests/unit/swagger/definitionsGeneration/metadata.spec.ts
@@ -480,7 +480,7 @@ describe('Metadata generation', () => {
     const parameterMetadata = new MetadataGenerator('./tests/fixtures/controllers/hiddenMethodController.ts').Generate();
     const controller = parameterMetadata.controllers[0];
 
-    it('should mark methods as visible by default', () => {
+    it('should generate methods visible by default', () => {
       const method = controller.methods.find(m => m.name === 'normalGetMethod');
       if (!method) {
         throw new Error('Method normalGetMethod not defined!');
@@ -491,7 +491,7 @@ describe('Metadata generation', () => {
       expect(method.isHidden).to.equal(false);
     });
 
-    it('should mark methods as hidden', () => {
+    it('should generate hidden methods', () => {
       const method = controller.methods.find(m => m.name === 'hiddenGetMethod');
       if (!method) {
         throw new Error('Method hiddenGetMethod not defined!');
@@ -503,18 +503,6 @@ describe('Metadata generation', () => {
     });
   });
 
-  describe('HiddenControllerGenerator', () => {
-    const parameterMetadata = new MetadataGenerator('./tests/fixtures/controllers/hiddenController.ts').Generate();
-    const controller = parameterMetadata.controllers[0];
-
-    it('should mark all methods as hidden', () => {
-      expect(controller.methods).to.have.lengthOf(2);
-      controller.methods.forEach(method => {
-        expect(method.isHidden).to.equal(true);
-      });
-    });
-  });
-
   describe('DeprecatedMethodGenerator', () => {
     const parameterMetadata = new MetadataGenerator('./tests/fixtures/controllers/deprecatedController.ts').Generate();
     const controller = parameterMetadata.controllers[0];
diff --git a/tests/unit/swagger/schemaDetails.spec.ts b/tests/unit/swagger/schemaDetails.spec.ts
index dacc6ba1..e1d8c12a 100644
--- a/tests/unit/swagger/schemaDetails.spec.ts
+++ b/tests/unit/swagger/schemaDetails.spec.ts
@@ -1,7 +1,5 @@
-import 'mocha';
-
 import { expect } from 'chai';
-
+import 'mocha';
 import { MetadataGenerator } from '../../../src/metadataGeneration/metadataGenerator';
 import { SpecGenerator2 } from '../../../src/swagger/specGenerator2';
 import { getDefaultOptions } from '../../fixtures/defaultOptions';
@@ -54,22 +52,4 @@ describe('Schema details generation', () => {
   }
 
   it('should set API license if provided', () => expect(licenseName).to.equal(getDefaultOptions().license));
-
-  describe('paths', () => {
-    describe('hidden paths', () => {
-      it('should not contain hidden paths', () => {
-        const metadataHiddenMethod = new MetadataGenerator('./tests/fixtures/controllers/hiddenMethodController.ts').Generate();
-        const specHiddenMethod = new SpecGenerator2(metadataHiddenMethod, getDefaultOptions()).GetSpec();
-
-        expect(specHiddenMethod.paths).to.have.keys(['/Controller/normalGetMethod']);
-      });
-
-      it('should not contain paths for hidden controller', () => {
-        const metadataHiddenController = new MetadataGenerator('./tests/fixtures/controllers/hiddenController.ts').Generate();
-        const specHiddenController = new SpecGenerator2(metadataHiddenController, getDefaultOptions()).GetSpec();
-
-        expect(specHiddenController.paths).to.be.empty;
-      });
-    });
-  });
 });
diff --git a/tests/unit/swagger/schemaDetails3.spec.ts b/tests/unit/swagger/schemaDetails3.spec.ts
index de262a9e..b559e998 100644
--- a/tests/unit/swagger/schemaDetails3.spec.ts
+++ b/tests/unit/swagger/schemaDetails3.spec.ts
@@ -130,21 +130,6 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
         });
       });
     });
-    describe('hidden paths', () => {
-      it('should not contain hidden paths', () => {
-        const metadataHiddenMethod = new MetadataGenerator('./tests/fixtures/controllers/hiddenMethodController.ts').Generate();
-        const specHiddenMethod = new SpecGenerator3(metadataHiddenMethod, getDefaultOptions()).GetSpec();
-
-        expect(specHiddenMethod.paths).to.have.keys(['/Controller/normalGetMethod']);
-      });
-
-      it('should not contain paths for hidden controller', () => {
-        const metadataHiddenController = new MetadataGenerator('./tests/fixtures/controllers/hiddenController.ts').Generate();
-        const specHiddenController = new SpecGenerator3(metadataHiddenController, getDefaultOptions()).GetSpec();
-
-        expect(specHiddenController.paths).to.be.empty;
-      });
-    });
   });
 
   describe('components', () => {
@@ -428,6 +413,15 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
             expect(propertySchema.enum).to.include('true', `for property ${propertyName}.enum`);
             expect(propertySchema.enum).to.include('false', `for property ${propertyName}.enum`);
           },
+          singleFloatLiteralType: (propertyName, propertySchema) => {
+            expect(propertySchema.type).to.eq('string', `for property ${propertyName}.type`);
+            expect(propertySchema['nullable']).to.eq(true, `for property ${propertyName}[x-nullable]`);
+            if (!propertySchema.enum) {
+              throw new Error(`There was no 'enum' property on ${propertyName}.`);
+            }
+            expect(propertySchema.enum).to.have.length(1, `for property ${propertyName}.enum`);
+            expect(propertySchema.enum).to.include('3.1415', `for property ${propertyName}.enum`);
+          },
           dateValue: (propertyName, propertySchema) => {
             expect(propertySchema.type).to.eq('string', `for property ${propertyName}.type`);
             expect(propertySchema.nullable).to.eq(true, `for property ${propertyName}.nullable`);