Repository: asyncapi/modelina
Pull request #732 (2022-04-26 14:17:39)

refactor: convert Go to new constraint setup
**Description**
This PR converts the Go generator to the new constraint setup introduced in #725 


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=732)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL) [29 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=732) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=732&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=732&metric=new_duplicated_lines_density&view=list)


jonaslagoni: > Kindly remove the code smell

@Samridhi-98 done 😆 

Think Sonar choked a bit before as those issues should not be present. Thanks for pointing them out 👍 
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=732)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=732&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=732) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=732&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/src/generators/go/GoConstrainer.ts b/src/generators/go/GoConstrainer.ts
index 76352ab3..72b5d8ee 100644
--- a/src/generators/go/GoConstrainer.ts
+++ b/src/generators/go/GoConstrainer.ts
@@ -1,200 +1,53 @@
-import { ConstrainedAnyModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedArrayModel, ConstrainedUnionModel, ConstrainedEnumModel, ConstrainedDictionaryModel, ConstrainedEnumValueModel } from '../../models/ConstrainedMetaModel';
-import { AnyModel, BooleanModel, FloatModel, IntegerModel, MetaModel, ObjectModel, ReferenceModel, StringModel, TupleModel, ArrayModel, UnionModel, EnumModel, DictionaryModel } from '../../models/MetaModel';
-import { defaultPropertyKeyConstraints, PropertyKeyConstraintType } from './constrainer/PropertyKeyConstrainer';
-import { defaultModelNameConstraints, ModelNameConstraintType } from './constrainer/ModelNameConstrainer';
-import { defaultEnumKeyConstraints, EnumConstraintType } from './constrainer/EnumConstrainer';
-
-export interface GoConstraints {
-  enumKey: EnumConstraintType,
-  modelName: ModelNameConstraintType,
-  propertyKey: PropertyKeyConstraintType,
-}
+import { TypeMapping } from '../../helpers';
+import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer';
+import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer';
+import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer';
+import { GoRenderer } from './GoRenderer';
+
+export const GoDefaultTypeMapping: TypeMapping<GoRenderer> = {
+  Object ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Reference ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Any (): string {
+    return 'interface{}';
+  },
+  Float (): string {
+    return 'float64';
+  },
+  Integer (): string {
+    return 'int'; 
+  },
+  String (): string {
+    return 'string';
+  },
+  Boolean (): string {
+    return 'bool';
+  },
+  Tuple (): string {
+    //Because Java have no notion of tuples (and no custom implementation), we have to render it as a list of any value.
+    return '[]interface{}';
+  },
+  Array ({constrainedModel}): string {
+    return `[]${constrainedModel.valueModel.type}`;
+  },
+  Enum ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Union (): string {
+    //Because Java have no notion of unions (and no custom implementation), we have to render it as any value.
+    return 'interface{}';
+  },
+  Dictionary ({constrainedModel}): string {
+    return `map[${constrainedModel.key.type}]${constrainedModel.value.type}`;
+  }
+};
 
-export const DefaultGoConstraints: GoConstraints = {
+export const GoDefaultConstraints = {
   enumKey: defaultEnumKeyConstraints(),
+  enumValue: defaultEnumValueConstraints(),
   modelName: defaultModelNameConstraints(),
   propertyKey: defaultPropertyKeyConstraints()
 };
-
-type TypeMappingFunction<T extends ConstrainedMetaModel> = (model: T) => string;
-
-type TypeMapping = {
-  Object?: TypeMappingFunction<ConstrainedObjectModel>,
-  Reference?: TypeMappingFunction<ConstrainedReferenceModel>,
-  Any?: TypeMappingFunction<ConstrainedAnyModel>,
-  Float?: TypeMappingFunction<ConstrainedFloatModel>,
-  Integer?: TypeMappingFunction<ConstrainedIntegerModel>,
-  String?: TypeMappingFunction<ConstrainedStringModel>,
-  Boolean?: TypeMappingFunction<ConstrainedBooleanModel>,
-  Tuple?: TypeMappingFunction<ConstrainedTupleModel>,
-  Array?: TypeMappingFunction<ConstrainedArrayModel>,
-  Enum?: TypeMappingFunction<ConstrainedEnumModel>,
-  Union?: TypeMappingFunction<ConstrainedUnionModel>,
-  Dictionary?: TypeMappingFunction<ConstrainedDictionaryModel>
-}
-
-function constrainReferenceModel(constrainedName: string, metaModel: ReferenceModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedReferenceModel {
-  const constrainedRefModel = constrainMetaModel(metaModel.ref, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedReferenceModel(constrainedName, metaModel.originalInput, '', constrainedRefModel);
-  if (typeMapping.Reference !== undefined) {
-    constrainedModel.type = typeMapping.Reference(constrainedModel);
-  } else {
-    constrainedModel.type = constrainedModel.name;
-  }
-  return constrainedModel;
-}
-function constrainAnyModel(constrainedName: string, metaModel: AnyModel, typeMapping: TypeMapping): ConstrainedAnyModel {
-  const constrainedModel = new ConstrainedAnyModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Any !== undefined) {
-    constrainedModel.type = typeMapping.Any(constrainedModel);
-  } else {
-    constrainedModel.type = 'interface{}';
-  }
-  return constrainedModel; 
-}
-function constrainFloatModel(constrainedName: string, metaModel: FloatModel, typeMapping: TypeMapping): ConstrainedFloatModel {
-  const constrainedModel = new ConstrainedFloatModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Float !== undefined) {
-    constrainedModel.type = typeMapping.Float(constrainedModel);
-  } else {
-    constrainedModel.type = 'float64';
-  }
-  return constrainedModel;
-}
-function constrainIntegerModel(constrainedName: string, metaModel: IntegerModel, typeMapping: TypeMapping): ConstrainedIntegerModel {
-  const constrainedModel = new ConstrainedIntegerModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Integer !== undefined) {
-    constrainedModel.type = typeMapping.Integer(constrainedModel);
-  } else {
-    constrainedModel.type = 'int';
-  }
-  return constrainedModel;
-}
-function constrainStringModel(constrainedName: string, metaModel: IntegerModel, typeMapping: TypeMapping): ConstrainedIntegerModel {
-  const constrainedModel = new ConstrainedStringModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.String !== undefined) {
-    constrainedModel.type = typeMapping.String(constrainedModel);
-  } else {
-    constrainedModel.type = 'string';
-  }
-  return constrainedModel;
-}
-function constrainBooleanModel(constrainedName: string, metaModel: BooleanModel, typeMapping: TypeMapping): ConstrainedBooleanModel {
-  const constrainedModel = new ConstrainedBooleanModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Boolean !== undefined) {
-    constrainedModel.type = typeMapping.Boolean(constrainedModel);
-  } else {
-    constrainedModel.type = 'bool';
-  }
-  return constrainedModel;
-}
-function constrainTupleModel(constrainedName: string, metaModel: TupleModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedTupleModel {
-  const constrainedTupleModels = metaModel.tuple.map((tupleValue) => {
-    const tupleType = constrainMetaModel(tupleValue.value, typeMapping, constrainRules);
-    return new ConstrainedTupleValueModel(tupleValue.index, tupleType);
-  });
-  const constrainedModel = new ConstrainedTupleModel(constrainedName, metaModel.originalInput, '', constrainedTupleModels);
-  if (typeMapping.Tuple !== undefined) {
-    constrainedModel.type = typeMapping.Tuple(constrainedModel);
-  } else {
-    const tupleType = '[]interface{}';
-    constrainedModel.type = tupleType;
-  }
-  return constrainedModel;
-}
-function constrainArrayModel(constrainedName: string, metaModel: ArrayModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedArrayModel {
-  const constrainedValueModel = constrainMetaModel(metaModel.valueModel, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedArrayModel(constrainedName, metaModel.originalInput, '', constrainedValueModel);
-  if (typeMapping.Array !== undefined) {
-    constrainedModel.type = typeMapping.Array(constrainedModel);
-  } else {
-    constrainedModel.type = `[]${constrainedValueModel.type}`;
-  }
-  return constrainedModel;
-}
-function constrainUnionModel(constrainedName: string, metaModel: UnionModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedUnionModel {
-  const constrainedUnionModels = metaModel.union.map((unionValue) => {
-    return constrainMetaModel(unionValue, typeMapping, constrainRules);
-  });
-  const constrainedModel = new ConstrainedUnionModel(constrainedName, metaModel.originalInput, '', constrainedUnionModels);
-  if (typeMapping.Union !== undefined) {
-    constrainedModel.type = typeMapping.Union(constrainedModel);
-  } else {
-    constrainedModel.type = 'interface{}';
-  }
-  return constrainedModel;
-}
-function constrainDictionaryModel(constrainedName: string, metaModel: DictionaryModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedDictionaryModel {
-  const keyModel = constrainMetaModel(metaModel.key, typeMapping, constrainRules);
-  const valueModel = constrainMetaModel(metaModel.value, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedDictionaryModel(constrainedName, metaModel.originalInput, '', keyModel, valueModel, metaModel.serializationType);
-  if (typeMapping.Dictionary !== undefined) {
-    constrainedModel.type = typeMapping.Dictionary(constrainedModel);
-  } else {
-    const type = `map[${keyModel.type}]${valueModel.type}`;
-    constrainedModel.type = type;
-  }
-  return constrainedModel;
-}
-
-function constrainObjectModel(constrainedName: string, objectModel: ObjectModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedObjectModel {
-  const constrainedObjectModel = new ConstrainedObjectModel(constrainedName, objectModel.originalInput, '', {});
-  for (const [propertyKey, propertyMetaModel] of Object.entries(objectModel.properties)) {
-    const constrainedPropertyName = constrainRules.propertyKey({propertyKey, constrainedObjectModel, objectModel});
-    const constrainedProperty = constrainMetaModel(propertyMetaModel, typeMapping, constrainRules);
-    constrainedObjectModel.properties[String(constrainedPropertyName)] = constrainedProperty;
-  }
-  if (typeMapping.Object !== undefined) {
-    constrainedObjectModel.type = typeMapping.Object(constrainedObjectModel);
-  } else {
-    constrainedObjectModel.type = constrainedName;
-  }
-  return constrainedObjectModel;
-}
-
-export function ConstrainEnumModel(constrainedName: string, enumModel: EnumModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedEnumModel {
-  const constrainedModel = new ConstrainedEnumModel(constrainedName, enumModel.originalInput, '', []);
-
-  for (const enumValue of enumModel.values) {
-    const constrainedEnumKey = constrainRules.enumKey({enumKey: String(enumValue.key), enumModel, constrainedEnumModel: constrainedModel});
-    const constrainedEnumValueModel = new ConstrainedEnumValueModel(constrainedEnumKey, enumValue.value);
-    constrainedModel.values.push(constrainedEnumValueModel);
-  }
-  if (typeMapping.Enum !== undefined) {
-    constrainedModel.type = typeMapping.Enum(constrainedModel);
-  } else {
-    constrainedModel.type = constrainedName;
-  }
-  return constrainedModel;
-}
-
-export function constrainMetaModel(metaModel: MetaModel, typeMapping: TypeMapping, constrainRules: GoConstraints): ConstrainedMetaModel {
-  const constrainedName = constrainRules.modelName({modelName: metaModel.name});
-  
-  if (metaModel instanceof ObjectModel) {
-    return constrainObjectModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof ReferenceModel) {
-    return constrainReferenceModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof AnyModel) {
-    return constrainAnyModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof FloatModel) {
-    return constrainFloatModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof IntegerModel) {
-    return constrainIntegerModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof StringModel) {
-    return constrainStringModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof BooleanModel) {
-    return constrainBooleanModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof TupleModel) {
-    return constrainTupleModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof ArrayModel) {
-    return constrainArrayModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof UnionModel) {
-    return constrainUnionModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof EnumModel) {
-    return ConstrainEnumModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof DictionaryModel) {
-    return constrainDictionaryModel(constrainedName, metaModel, typeMapping, constrainRules);
-  }
-  throw new Error('Could not constrain model');
-}
diff --git a/src/generators/go/GoGenerator.ts b/src/generators/go/GoGenerator.ts
index 991545e7..0dba3941 100644
--- a/src/generators/go/GoGenerator.ts
+++ b/src/generators/go/GoGenerator.ts
@@ -4,13 +4,15 @@ import {
   defaultGeneratorOptions
 } from '../AbstractGenerator';
 import { CommonModel, CommonInputModel, RenderOutput } from '../../models';
-import { TypeHelpers, ModelKind, FormatHelpers } from '../../helpers';
+import { TypeHelpers, ModelKind, FormatHelpers, Constraints, TypeMapping } from '../../helpers';
 import { GoPreset, GO_DEFAULT_PRESET } from './GoPreset';
 import { StructRenderer } from './renderers/StructRenderer';
 import { EnumRenderer } from './renderers/EnumRenderer';
 import { pascalCaseTransformMerge } from 'change-case';
 import { Logger } from '../../utils/LoggingInterface';
 import { isReservedGoKeyword } from './Constants';
+import { GoDefaultConstraints, GoDefaultTypeMapping } from './GoConstrainer';
+import { GoRenderer } from './GoRenderer';
 /**
  * The Go naming convention type
  */
@@ -48,6 +50,8 @@ export const GoNamingConventionImplementation: GoNamingConvention = {
 
 export interface GoOptions extends CommonGeneratorOptions<GoPreset> {
   namingConvention?: GoNamingConvention;
+  typeMapping: TypeMapping<GoRenderer>;
+  constraints: Constraints
 }
 
 export interface GoRenderCompleteModelOptions {
@@ -61,12 +65,16 @@ export class GoGenerator extends AbstractGenerator<GoOptions, GoRenderCompleteMo
   static defaultOptions: GoOptions = {
     ...defaultGeneratorOptions,
     defaultPreset: GO_DEFAULT_PRESET,
-    namingConvention: GoNamingConventionImplementation
+    namingConvention: GoNamingConventionImplementation,
+    typeMapping: GoDefaultTypeMapping,
+    constraints: GoDefaultConstraints
   };
   constructor(
-    options: GoOptions = GoGenerator.defaultOptions,
+    options: Partial<GoOptions> = GoGenerator.defaultOptions,
   ) {
-    super('Go', GoGenerator.defaultOptions, options);
+    const mergedOptions = {...GoGenerator.defaultOptions, ...options};
+
+    super('Go', GoGenerator.defaultOptions, mergedOptions);
   }
   reservedGoKeyword(name: string): boolean {
     return isReservedGoKeyword(name);
diff --git a/src/generators/go/constrainer/EnumConstrainer.ts b/src/generators/go/constrainer/EnumConstrainer.ts
index d9195e35..ce4e03c7 100644
--- a/src/generators/go/constrainer/EnumConstrainer.ts
+++ b/src/generators/go/constrainer/EnumConstrainer.ts
@@ -1,7 +1,7 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedEnumModel, EnumModel } from '../../../models';
-import { NO_NUMBER_START_CHAR, NO_DUPLICATE_ENUM_KEYS, NO_EMPTY_VALUE} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { NO_NUMBER_START_CHAR, NO_DUPLICATE_ENUM_KEYS, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS } from '../../../helpers/Constraints';
+import { FormatHelpers, EnumKeyConstraint, EnumValueConstraint } from '../../../helpers';
+import { isReservedGoKeyword } from '../Constants';
 
 export type ModelEnumKeyConstraints = {
   NO_SPECIAL_CHAR: (value: string) => string;
@@ -22,44 +22,27 @@ export const DefaultEnumKeyConstraints: ModelEnumKeyConstraints = {
   NO_EMPTY_VALUE,
   NAMING_FORMATTER: FormatHelpers.toConstantCase,
   NO_RESERVED_KEYWORDS: (value: string) => {
-    return value;
+    return NO_RESERVED_KEYWORDS(value, isReservedGoKeyword); 
   }
 };
 
-export type EnumKeyContext = {
-  enumKey: string,
-  constrainedEnumModel: ConstrainedEnumModel,
-  enumModel: EnumModel
-}
-export type EnumConstraintType = (context: EnumKeyContext, constraints?: ModelEnumKeyConstraints) => string;
+export function defaultEnumKeyConstraints(customConstraints?: Partial<ModelEnumKeyConstraints>): EnumKeyConstraint {
+  const constraints = {...DefaultEnumKeyConstraints, ...customConstraints};
 
-export function defaultEnumKeyConstraints(customConstraints?: ModelEnumKeyConstraints): EnumConstraintType {
-  const constraints = DefaultEnumKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NO_RESERVED_KEYWORDS = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-    if (customConstraints.NO_DUPLICATE_KEYS !== undefined) {
-      constraints.NO_DUPLICATE_KEYS = customConstraints.NO_DUPLICATE_KEYS;
-    }
-  }
   return ({enumKey, enumModel, constrainedEnumModel}) => {
     let constrainedEnumKey = enumKey;
-    constrainedEnumKey = constraints.NO_SPECIAL_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_EMPTY_VALUE!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NAMING_FORMATTER!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS!(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER!);
+    constrainedEnumKey = constraints.NO_SPECIAL_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey);
+    constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
     return constrainedEnumKey;
   };
 }
+
+export function defaultEnumValueConstraints(): EnumValueConstraint {
+  return ({enumValue}) => {
+    return `"${enumValue}"`;
+  };
+}
diff --git a/src/generators/go/constrainer/ModelNameConstrainer.ts b/src/generators/go/constrainer/ModelNameConstrainer.ts
index 21c4bc4d..f8d8e578 100644
--- a/src/generators/go/constrainer/ModelNameConstrainer.ts
+++ b/src/generators/go/constrainer/ModelNameConstrainer.ts
@@ -1,13 +1,13 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import { NO_NUMBER_START_CHAR, NO_EMPTY_VALUE} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS } from '../../../helpers/Constraints';
+import { FormatHelpers, ModelNameConstraint } from '../../../helpers';
+import { isReservedGoKeyword } from '../Constants';
 
 export type ModelNameConstraints = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
-  NO_RESERVED_KEYWORDS?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultModelNameConstraints: ModelNameConstraints = {
@@ -22,41 +22,20 @@ export const DefaultModelNameConstraints: ModelNameConstraints = {
     return FormatHelpers.toPascalCase(value);
   },
   NO_RESERVED_KEYWORDS: (value: string) => {
-    return value;
+    return NO_RESERVED_KEYWORDS(value, isReservedGoKeyword); 
   }
 };
-export type ModelNameContext = {
-  modelName: string
-}
-export type ModelNameConstraintType = (context: ModelNameContext) => string;
 
-export function defaultModelNameConstraints(customConstraints?: ModelNameConstraints): ModelNameConstraintType {
-  const constraints = DefaultModelNameConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-  }
+export function defaultModelNameConstraints(customConstraints?: Partial<ModelNameConstraints>): ModelNameConstraint {
+  const constraints = {...DefaultModelNameConstraints, ...customConstraints};
 
   return ({modelName}) => {
     let constrainedValue = modelName;
-    constrainedValue = constraints.NO_SPECIAL_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_NUMBER_START_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_EMPTY_VALUE!(constrainedValue);
-    constrainedValue = constraints.NAMING_FORMATTER!(constrainedValue);
-    constrainedValue = constraints.NO_RESERVED_KEYWORDS!(constrainedValue);
+    constrainedValue = constraints.NO_SPECIAL_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_NUMBER_START_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_EMPTY_VALUE(constrainedValue);
+    constrainedValue = constraints.NO_RESERVED_KEYWORDS(constrainedValue);
+    constrainedValue = constraints.NAMING_FORMATTER(constrainedValue);
     return constrainedValue;
   };
 }
diff --git a/src/generators/go/constrainer/PropertyKeyConstrainer.ts b/src/generators/go/constrainer/PropertyKeyConstrainer.ts
index bab65778..bc2b32df 100644
--- a/src/generators/go/constrainer/PropertyKeyConstrainer.ts
+++ b/src/generators/go/constrainer/PropertyKeyConstrainer.ts
@@ -1,14 +1,15 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedObjectModel, ObjectModel } from '../../../models';
-import { NO_NUMBER_START_CHAR, NO_DUPLICATE_PROPERTIES, NO_EMPTY_VALUE} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { NO_NUMBER_START_CHAR, NO_DUPLICATE_PROPERTIES, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS } from '../../../helpers/Constraints';
+import { FormatHelpers, PropertyKeyConstraint } from '../../../helpers';
+import { isReservedGoKeyword } from '../Constants';
 
 export type PropertyKeyConstraintOptions = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_DUPLICATE_PROPERTIES?: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_DUPLICATE_PROPERTIES: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
@@ -21,43 +22,23 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
   NO_DUPLICATE_PROPERTIES,
   NO_EMPTY_VALUE,
   NAMING_FORMATTER: FormatHelpers.toPascalCase,
+  NO_RESERVED_KEYWORDS: (value: string) => {
+    return NO_RESERVED_KEYWORDS(value, isReservedGoKeyword); 
+  }
 };
 
-export type PropertyKeyContext = {
-  propertyKey: string,
-  constrainedObjectModel: ConstrainedObjectModel,
-  objectModel: ObjectModel
-}
-
-export type PropertyKeyConstraintType = (context: PropertyKeyContext) => string;
+export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
+  const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};
 
-export function defaultPropertyKeyConstraints(customConstraints?: PropertyKeyConstraintOptions): PropertyKeyConstraintType {
-  const constraints = DefaultPropertyKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NO_DUPLICATE_PROPERTIES !== undefined) {
-      constraints.NO_DUPLICATE_PROPERTIES = customConstraints.NO_DUPLICATE_PROPERTIES;
-    }
-  }
-  return ({propertyKey, constrainedObjectModel, objectModel}: PropertyKeyContext) => {
+  return ({propertyKey, constrainedObjectModel, objectModel}) => {
     let constrainedPropertyKey = propertyKey;
 
-    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_EMPTY_VALUE!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NAMING_FORMATTER!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES!(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER!);
+    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
     return constrainedPropertyKey;
   };
 }


Test patch:
diff --git a/test/TestUtils/TestRenderers.ts b/test/TestUtils/TestRenderers.ts
index 590e6f17..8c6404d4 100644
--- a/test/TestUtils/TestRenderers.ts
+++ b/test/TestUtils/TestRenderers.ts
@@ -1,4 +1,5 @@
 import { AbstractRenderer, CommonInputModel, CommonModel, RenderOutput } from '../../src';
+import { GoRenderer } from '../../src/generators/go/GoRenderer';
 import { CSharpRenderer } from '../../src/generators/csharp/CSharpRenderer';
 import { JavaRenderer } from '../../src/generators/java/JavaRenderer';
 import {testOptions, TestGenerator} from './TestGenerator';
@@ -13,4 +14,6 @@ export class TestRenderer extends AbstractRenderer {
 }
 
 export class MockJavaRenderer extends JavaRenderer {}
+export class MockGoRenderer extends GoRenderer {}
 export class MockCSharpRenderer extends CSharpRenderer {}
+
diff --git a/test/generators/go/GoConstrainer.spec.ts b/test/generators/go/GoConstrainer.spec.ts
new file mode 100644
index 00000000..58a281b6
--- /dev/null
+++ b/test/generators/go/GoConstrainer.spec.ts
@@ -0,0 +1,103 @@
+import {GoDefaultTypeMapping } from '../../../src/generators/go/GoConstrainer';
+import {MockGoRenderer} from '../../TestUtils/TestRenderers';
+import { GoRenderer } from '../../../src/generators/go/GoRenderer';
+import { CommonInputModel, CommonModel, ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedUnionModel, GoGenerator } from '../../../src';
+describe('GoConstrainer', () => {
+  let renderer: GoRenderer;
+  beforeEach(() => {
+    renderer = new MockGoRenderer(GoGenerator.defaultOptions, new GoGenerator(), [], new CommonModel(), new CommonInputModel());
+  });
+  describe('ObjectModel', () => { 
+    test('should render the constrained name as type', () => {
+      const model = new ConstrainedObjectModel('test', undefined, '', {});
+      const type = GoDefaultTypeMapping.Object({constrainedModel: model, renderer});
+      expect(type).toEqual(model.name);
+    });
+  });
+  describe('Reference', () => { 
+    test('should render the constrained name as type', () => {
+      const refModel = new ConstrainedAnyModel('test', undefined, '');
+      const model = new ConstrainedReferenceModel('test', undefined, '', refModel);
+      const type = GoDefaultTypeMapping.Reference({constrainedModel: model, renderer});
+      expect(type).toEqual(model.name);
+    });
+  });
+  describe('Any', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedAnyModel('test', undefined, '');
+      const type = GoDefaultTypeMapping.Any({constrainedModel: model, renderer});
+      expect(type).toEqual('interface{}');
+    });
+  });
+  describe('Float', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedFloatModel('test', undefined, '');
+      const type = GoDefaultTypeMapping.Float({constrainedModel: model, renderer});
+      expect(type).toEqual('float64');
+    });
+  });
+  describe('Integer', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedIntegerModel('test', undefined, '');
+      const type = GoDefaultTypeMapping.Integer({constrainedModel: model, renderer});
+      expect(type).toEqual('int');
+    });
+  });
+  describe('String', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedStringModel('test', undefined, '');
+      const type = GoDefaultTypeMapping.String({constrainedModel: model, renderer});
+      expect(type).toEqual('string');
+    });
+  });
+  describe('Boolean', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedBooleanModel('test', undefined, '');
+      const type = GoDefaultTypeMapping.Boolean({constrainedModel: model, renderer});
+      expect(type).toEqual('bool');
+    });
+  });
+
+  describe('Tuple', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedTupleModel('test', undefined, '', []);
+      const type = GoDefaultTypeMapping.Tuple({constrainedModel: model, renderer});
+      expect(type).toEqual('[]interface{}');
+    });
+  });
+
+  describe('Array', () => { 
+    test('should render type', () => {
+      const arrayModel = new ConstrainedStringModel('test', undefined, 'string');
+      const model = new ConstrainedArrayModel('test', undefined, '', arrayModel);
+      const type = GoDefaultTypeMapping.Array({constrainedModel: model, renderer});
+      expect(type).toEqual('[]string');
+    });
+  });
+
+  describe('Enum', () => { 
+    test('should render the constrained name as type', () => {
+      const model = new ConstrainedEnumModel('test', undefined, '', []);
+      const type = GoDefaultTypeMapping.Enum({constrainedModel: model, renderer});
+      expect(type).toEqual(model.name);
+    });
+  });
+
+  describe('Union', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedUnionModel('test', undefined, '', []);
+      const type = GoDefaultTypeMapping.Union({constrainedModel: model, renderer});
+      expect(type).toEqual('interface{}');
+    });
+  });
+
+  describe('Dictionary', () => { 
+    test('should render type', () => {
+      const keyModel = new ConstrainedStringModel('test', undefined, 'string');
+      const valueModel = new ConstrainedStringModel('test', undefined, 'string');
+      const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
+      const type = GoDefaultTypeMapping.Dictionary({constrainedModel: model, renderer});
+      expect(type).toEqual('map[string]string');
+    });
+  });
+});
diff --git a/test/generators/go/constrainer/EnumConstrainer.spec.ts b/test/generators/go/constrainer/EnumConstrainer.spec.ts
new file mode 100644
index 00000000..7d87c73e
--- /dev/null
+++ b/test/generators/go/constrainer/EnumConstrainer.spec.ts
@@ -0,0 +1,99 @@
+import { GoDefaultConstraints } from '../../../../src/generators/go/GoConstrainer';
+import {EnumModel} from '../../../../src/models/MetaModel';
+import { ConstrainedEnumModel, ConstrainedEnumValueModel } from '../../../../src';
+import { defaultEnumKeyConstraints, ModelEnumKeyConstraints, DefaultEnumKeyConstraints } from '../../../../src/generators/go/constrainer/EnumConstrainer';
+describe('EnumConstrainer', () => {
+  const enumModel = new EnumModel('test', undefined, []);
+  const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', []);
+
+  describe('enum keys', () => {
+    test('should never render special chars', () => {
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '%'});
+      expect(constrainedKey).toEqual('PERCENT');
+    });
+    test('should not render number as start char', () => {
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '1'});
+      expect(constrainedKey).toEqual('NUMBER_1');
+    });
+    test('should not contain duplicate keys', () => {
+      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TEST', 'test');
+      const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', [existingConstrainedEnumValueModel]);
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'TEST'});
+      expect(constrainedKey).toEqual('RESERVED_TEST');
+    });
+    test('should never contain empty keys', () => {
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedKey).toEqual('EMPTY');
+    });
+    test('should use constant naming format', () => {
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'some weird_value!"#2'});
+      expect(constrainedKey).toEqual('SOME_SPACE_WEIRD_VALUE_EXCLAMATION_QUOTATION_HASH_2');
+    });
+    test('should never render reserved keywords', () => {
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'return'});
+      expect(constrainedKey).toEqual('RESERVED_RETURN');
+    });
+  });
+  describe('enum values', () => {
+    test('should render string values', () => {
+      const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 'string value'});
+      expect(constrainedValue).toEqual('"string value"');
+    });
+    test('should render boolean values', () => {
+      const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: true});
+      expect(constrainedValue).toEqual('"true"');
+    });
+    test.skip('should render numbers', () => {
+      const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 123});
+      expect(constrainedValue).toEqual(123);
+    });
+    test.skip('should render object', () => {
+      const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: {test: 'test'}});
+      expect(constrainedValue).toEqual('"{\\"test\\":\\"test\\"}"');
+    });
+    test('should render unknown value', () => {
+      const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: undefined});
+      expect(constrainedValue).toEqual('"undefined"');
+    });
+  });
+  describe('custom constraints', () => {
+    test('should be able to handle undefined', () => {
+      const constrainFunction = defaultEnumKeyConstraints(undefined);
+      const value = constrainFunction({enumModel, constrainedEnumModel, enumKey: 'TEST'});
+      expect(value).toEqual('TEST');
+    });
+    test('should be able to overwrite all hooks for enum key', () => {
+      const mockedConstraintCallbacks: ModelEnumKeyConstraints = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_DUPLICATE_KEYS: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultEnumKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks for enum key', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_DUPLICATE_KEYS'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultEnumKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/go/constrainer/ModelNameConstrainer.spec.ts b/test/generators/go/constrainer/ModelNameConstrainer.spec.ts
new file mode 100644
index 00000000..3fec4ed1
--- /dev/null
+++ b/test/generators/go/constrainer/ModelNameConstrainer.spec.ts
@@ -0,0 +1,57 @@
+import { GoDefaultConstraints } from '../../../../src/generators/go/GoConstrainer';
+import { DefaultModelNameConstraints, defaultModelNameConstraints, ModelNameConstraints } from '../../../../src/generators/go/constrainer/ModelNameConstrainer';
+describe('ModelNameConstrainer', () => {
+  test('should never render special chars', () => {
+    const constrainedKey = GoDefaultConstraints.modelName({modelName: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should never render number as start char', () => {
+    const constrainedKey = GoDefaultConstraints.modelName({modelName: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = GoDefaultConstraints.modelName({modelName: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = GoDefaultConstraints.modelName({modelName: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = GoDefaultConstraints.modelName({modelName: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: ModelNameConstraints = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultModelNameConstraints(mockedConstraintCallbacks);
+      constrainFunction({modelName: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultModelNameConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultModelNameConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({modelName: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts
new file mode 100644
index 00000000..756cdbcb
--- /dev/null
+++ b/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts
@@ -0,0 +1,70 @@
+import { GoDefaultConstraints } from '../../../../src/generators/go/GoConstrainer';
+import { ConstrainedObjectModel, ObjectModel } from '../../../../src';
+import { DefaultPropertyKeyConstraints, defaultPropertyKeyConstraints, PropertyKeyConstraintOptions } from '../../../../src/generators/go/constrainer/PropertyKeyConstrainer';
+describe('PropertyKeyConstrainer', () => {
+  const objectModel = new ObjectModel('test', undefined, {});
+  const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
+
+  test('should never render special chars', () => {
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should not render number as start char', () => {
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should not contain duplicate properties', () => {
+    const objectModel = new ObjectModel('test', undefined, {});
+    const propertyModel = new ConstrainedObjectModel('SomeProperty', undefined, '', {});
+    const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {SomeProperty: propertyModel});
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'SomeProperty'});
+    expect(constrainedKey).toEqual('ReservedSomeProperty');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: PropertyKeyConstraintOptions = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue(''),
+        NO_DUPLICATE_PROPERTIES: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_RESERVED_KEYWORDS'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_DUPLICATE_PROPERTIES')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});