helper class for interaction with source code. The class takes several source code files as parameters and allows access to the syntax and semantic information of the classes. This class now also has a fluent API to add source code on the fly. Before using the fluent API, ensure that you call New() to erase all existing content (if desired) and at the end, call Compile() to generate a compilation unit and a semantic model from the collected source code.
        private ClassDeclarationSyntax ImplementInterfaceByChild(string childClassName)
        {
            var sourceCode = new SourceCode(Files.Interface);
            var childClass = sourceCode.Class(childClassName);
            var startPos = childClass.GetLocation().SourceSpan.Start;

            // create a mixin class that implements an interface
            var mixin = Substitute.For<MixinReference>();
            var @class = Substitute.For<ClassWithTypeSymbol>();
            @class.IsInterface.Returns(false);
            @class.Interfaces.Returns(
                new InterfaceList(
                    new Interface(sourceCode.GetTypeByName(nameof(IFirstInterface)))));

            mixin.Class.Returns(@class);

            var interfaces = new InterfaceList(new[] 
            {
                new Interface(sourceCode.GetTypeByName(nameof(IFirstInterface)))
            });
            var addInterfaceWriter = new AddInterfacesToChildSyntaxWriter(mixin,sourceCode.Semantic, startPos);
            var newChildClass = addInterfaceWriter.Visit(childClass);

            return (ClassDeclarationSyntax)newChildClass;
        }
        public void ChildWithOneInterface_IncludeMixinWithManyInterfaces_OnlyMissingInterfacesAdded()
        {
            var sourceCode = new SourceCode(Files.Interface);
            var childClass = sourceCode.Class(nameof(ChildWithInterface));
            var startPos = childClass.GetLocation().SourceSpan.Start;
            var interfaces = new InterfaceList(new[] 
            {
                new Interface(sourceCode.GetTypeByName(nameof(IFirstInterface))),
                new Interface(sourceCode.GetTypeByName(nameof(ISecondInterface))) 
            });

            var @class = Substitute.For<ClassWithTypeSymbol>();
            @class.IsInterface.Returns(false);
            @class.Interfaces.Returns(interfaces);
            var mixin = Substitute.For<MixinReference>();
            mixin.Class.Returns(@class);

            var addInterfaceWriter = new AddInterfacesToChildSyntaxWriter(mixin, sourceCode.Semantic, startPos);
            var newChildClass = (ClassDeclarationSyntax)addInterfaceWriter.Visit(childClass);

            var baseList = newChildClass.BaseList.Types;
            // assert: child class should have both interfaces
            Assert.AreEqual(2, baseList.Count);
            Assert.IsNotNull(
                baseList.Single(x => x.TypeName() == nameof(IFirstInterface)));
            Assert.IsNotNull(
                baseList.Single(x => x.TypeName() == nameof(ISecondInterface)));
        }
Пример #3
0
        public void ClassWithBaseClass_CreateFromSymbol_ClassAndBaseClassCreated()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Person);
            var personClass = sourceCode.Class(nameof(ThirdPersonClass));

            var classFactory = new ClassFactory(sourceCode.Semantic);
            var @class = classFactory.Create(personClass);

            Assert.IsFalse(@class.Properties.Any());
            Assert.AreEqual("Name", @class.BaseClass.BaseClass.Properties.Single().Name);            
        }
Пример #4
0
        public void ClassFactory_CreateFromCode_ClassCreated()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Person);
            var personClass = sourceCode.Class(nameof(WorkingPerson));

            var classFactory = new ClassFactory(sourceCode.Semantic);
            var @class = classFactory.Create(personClass);

            Assert.AreEqual("Name", @class.Properties.Single().Name);
            Assert.AreEqual("void Work(int toolNumber)", @class.Methods.Single().ToString());
        }
Пример #5
0
        public void ClassWithMethodWithParameter_Read_MethodRead()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Worker);
            var workerClass = sourceCode.Class(nameof(WorkerWithTool));

            var methodList = new MethodList();

            var methodReader = new MethodSyntaxReader(methodList, sourceCode.Semantic);
            methodReader.Visit(workerClass);

            Assert.AreEqual(1, methodList.Count);
            Assert.AreEqual("void Work(int toolNumber)", methodList[0].ToString());
        }
        public void ClassWithProperty_Read_PropertyRead()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Person);
            var personClass = sourceCode.Class(nameof(PersonWithName));

            var propertyList = new PropertyList();

            var propertySyntaxReader = new PropertySyntaxReader(propertyList,sourceCode.Semantic);
            propertySyntaxReader.Visit(personClass);

            Assert.AreEqual(1, propertyList.Count);
            Assert.AreEqual("Name", propertyList[0].Name);
        }
Пример #7
0
        public void PropertiesInMixinAndChild_Mix_OnlyMissingPropertiesToImplement()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(PersonWithFullName));
            var mixinField = personClass.FindMixinReference("_name");

            var child = new ClassFactory(sourceCode.Semantic).Create(personClass);
            var mixin = new MixinReferenceFactory(sourceCode.Semantic).Create(mixinField);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // Assert: all properties of mixin should be implemented
            Assert.AreEqual(2, mixer.MembersToImplement.Count());
        }
Пример #8
0
        public void PropertiesInBaseClass_Mix_NoPropertyToImplement()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(ThirdPersonClass));
            var mixinField = personClass.FindMixinReference("_name");

            var child = new ClassFactory(sourceCode.Semantic).Create(personClass);
            var mixin = new MixinReferenceFactory(sourceCode.Semantic).Create(mixinField);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // Assert: all properties of mixin should be implemented
            Assert.IsEmpty(mixer.MembersToImplement);
        }
        public void ClassDeclarationWithLambda_ReadParameter_IgnoreLambdaParameter()
        {
            var sourceCode = new SourceCode(Files.Person);
            var personClass = sourceCode.Class(nameof(PersonWithLambdaMethod));

            var parameterList = new ParameterList();

            var parameterSyntaxReader = new ParameterSyntaxReader(parameterList, sourceCode.Semantic);
            parameterSyntaxReader.Visit(personClass);

            // the parameter that is used in the lambda expression should not
            // be added to the parameter list, but the method parameter should be
            Assert.AreEqual(1, parameterList.ParameterCount);
            Assert.AreEqual("methodParameter", parameterList.Single().Name);
        }
Пример #10
0
        public void MixinWithStaticMethod_Include_MethodNotIncluded()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Worker);
            var personClass = sourceCode.Class(nameof(PersonWithStaticMethodMixin));
            var mixinReference = personClass.FindMixinReference("_worker");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // no method to implement
            Assert.IsEmpty(mixer.MethodsToImplement);
        }
Пример #11
0
        public void MethodImplementedWithOtherParameter_Include_MethodIncluded()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Worker);
            var personClass = sourceCode.Class(nameof(PersonWithOtherWorkMethod));
            var mixinReference = personClass.FindMixinReference("_worker");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // no method to implement
            Assert.AreEqual(1,mixer.MethodsToImplement.Count(x => x.Name == "Work"));
        }
Пример #12
0
        public void MixinWithMethod_Include_MethodsIncluded()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Worker);
            var personClass = sourceCode.Class(nameof(Person));
            var mixinReference = personClass.FindMixinReference("_worker");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            Assert.AreEqual(mixer.MethodsToImplement.Count(), mixin.Class.Methods.Count());
            foreach (var service in mixin.Class.Methods)
                Assert.AreEqual(1, mixer.MethodsToImplement.Count(x => x.Name == service.Name));
        }
Пример #13
0
        public void MixinClassWithProperty_Include_PropertiesIncluded()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(Person));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // assert all properties of the mixin should have been added
            Assert.AreEqual(mixin.Class.Properties.Count(),mixer.PropertiesToImplement.Count());
            // check that every method of mixin appears only once in the child
            foreach (var service in mixin.Class.Properties)
                Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.Name == service.Name));
        }
Пример #14
0
        private void ValidateCommentForMember(string mixinReferenceName)
        {
            // arrange
            var sourceCode = new SourceCode(Files.Comments);
            var childClass = sourceCode.Class(nameof(Child));
            var mixinClass = new MixinReferenceFactory(sourceCode.Semantic)
                .Create(childClass.FindMixinReference(mixinReferenceName));
            var settings = new Settings(includeDocumentation: true);
            var mixinCommand = new IncludeMixinCommand(mixinClass);

            // act
            var newClassDeclaration = mixinCommand.Execute(
                childClass,
                sourceCode.Semantic,
                settings);

            Assert.IsTrue(
                ValidationHelpers.HasSameDocumentation(
                    newClassDeclaration, 
                    mixinCommand.Mixin));
        }
Пример #15
0
        public void MixinWithPropertyExpressionBody_Include_PropertyHasGetter()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(PersonWithGetterName));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            // 2. create instances for mixin and child mixin
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // assert. Only one property in resulting class
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count());
            // the expression body should be converted to a HasGetter
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.IsReadOnly));
        }
Пример #16
0
        public void MixinInterfaceWithProperty_Include_PropertiesIncluded()
        {
            // arrange
            // 1. load source files and get class and mixin declarations
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(Person));
            var mixinReference = personClass.FindMixinReference("_interfaceName");
            var semanticModel = sourceCode.Semantic;
            // 2. create instances for mixin and child mixin
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // assert. The child should have the same properties as the mixin
            Assert.AreEqual(mixin.Class.Properties.Count(), mixer.PropertiesToImplement.Count());
            // check that every method of mixin appears only once in the child
            foreach (var service in mixin.Class.Properties)
                Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.Name == service.Name));
        }
        public void AddDocumentationAndCreateRegion_Created()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Comments);
            var childClass = sourceCode.Class(nameof(Child));
            var mixinClass = 
                new MixinReferenceFactory(sourceCode.Semantic)
                .Create(childClass.FindMixinReference("_mixinWithProperty"));
            var settings = new Settings(includeDocumentation: true,createRegions: true);
            var mixinCommand = new IncludeMixinCommand(mixinClass);

            // act
            var newClassDeclaration = mixinCommand.Execute(childClass, sourceCode.Semantic,settings);

            // assert: there should be a region and a documentation
            var isPropertyBetweenRegion = IsPropertyBetweenRegion(
                newClassDeclaration, 
                "mixin _mixinWithProperty",
                "Property");
            var hasSameDocumentation = HasSameDocumentation(newClassDeclaration, mixinCommand.Mixin);
            Assert.IsTrue(isPropertyBetweenRegion);
            Assert.IsTrue(hasSameDocumentation);
        }
Пример #18
0
 protected void WithExternalAssemblyFromType(Type externalType)
 {
     _sourceCode = new SourceCode();
     _sourceCode.CompileFromAssemblyOfType(externalType);
 }
Пример #19
0
        public void MixinWithToString_Include_ToStringShouldBeImplemented()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Worker);
            var personClass = sourceCode.Class(nameof(PersonWithToString));
            var mixinReference = personClass.FindMixinReference("_toString");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // ToString should be in list of methods to override
            Assert.IsTrue(mixer.MethodsToImplement.Any(x => x.Name == "ToString"));
            // ToString in mixin must have override keyword
            Assert.IsTrue(mixer.MethodsToImplement.Single(x => x.Name == "ToString").IsOverrideFromObject);
        }
Пример #20
0
        public void ChildHasBaseClassWithBaseClassesWithProperty_Include_PropertyNotReimplemented()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(ThirdPersonClass));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // nothing to implement for the mixer, child already has property
            Assert.IsEmpty(mixer.PropertiesToImplement);
        }
Пример #21
0
 protected void WithSourceFiles(params string[] sourceFiles)
 {
     _sourceCode = new SourceCode(sourceFiles);
 }
Пример #22
0
        public void MixinWithStaticProperty_Include_PropertyNotImplemented()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(PersonWithStaticMixin));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // assert: Child should not have a "Name" property
            Assert.IsEmpty(mixer.PropertiesToImplement);
        }
Пример #23
0
        public void ChildHasInterfaceWithProperty_Include_PropertyImplemented()
        {
            // arrange
            var sourceCode = new SourceCode(Files.NotCompilable, Files.Name);
            var personClass = sourceCode.Class("DerivedFromInterfaceClass");
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // assert: Child should have one "Name" property
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.Name == "Name"));
            // this one property should have only getter (signature from interface and mixin is the same)
            Assert.IsTrue(mixer.PropertiesToImplement.Single(x => x.Name == "Name").IsReadOnly);
        }
Пример #24
0
        public void MixinWithGenericProperty_Include_PropertyImplemented()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(PersonWithGenericMixin));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // child should have "Name" property
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.Name == "Names"));
            // name property should be of type "IEnumerable<string>"
            var typeName = mixer.PropertiesToImplement.Single().Type.ToString();
            Assert.AreEqual("System.Collections.Generic.IEnumerable<string>", typeName);
        }
 public void MixinIsInterface_Include_MixinAddedAsInterface()
 {
     var sourceCode = new SourceCode(Files.Interface);
     var childClass = sourceCode.Class(nameof(ChildWithoutInterface));
     var startPos = childClass.GetLocation().SourceSpan.Start;
     // the mixin will be an interface
     var @class = Substitute.For<ClassWithTypeSymbol>();
     @class.IsInterface.Returns(true);
     @class.AsInterface().Returns(new Interface(sourceCode.GetTypeByName(nameof(IFirstInterface))));
     var mixin = Substitute.For<MixinReference>();
     mixin.Class.Returns(@class);
     // act
     var addInterfaceWriter = new AddInterfacesToChildSyntaxWriter(mixin, sourceCode.Semantic, startPos);
     var newChildClass = (ClassDeclarationSyntax)addInterfaceWriter.Visit(childClass);
     var baseList = newChildClass.BaseList.Types;
     // assert: child class should have the mixin as interface
     Assert.AreEqual(1, baseList.Count);
     Assert.IsNotNull(baseList.Single(x => x.TypeName() == nameof(IFirstInterface)));
 }
Пример #26
0
        public void MixinWithIndexer_Include_IndexerImplemented()
        {
            // arrange
            var sourceCode = new SourceCode(Files.Person, Files.Collection);
            var personClass = sourceCode.Class(nameof(PersonWithIndexer));
            var mixinReference = personClass.FindMixinReference("_collection");
            var semanticModel = sourceCode.Semantic;
            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            // act 
            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // child should also have an indexer property now
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count());
            Assert.AreEqual("string this[int index]", mixer.PropertiesToImplement.Single().ToString());            
        }
        public void MixinIsInterfaceInDifferentNamespace_Include_MixinAddedAsFullQualifiedInterface()
        {
            var sourceCode = new SourceCode(Files.Interface);
            var childClass = sourceCode.Class(nameof(ChildWithoutInterface));
            // changing the start position here will force the type resolver
            // to use a full qualified type name
            var startPos = 0;
            // the mixin will be an interface
            var @class = Substitute.For<ClassWithTypeSymbol>();
            @class.IsInterface.Returns(true);
            @class.AsInterface().Returns(new Interface(
                sourceCode.GetTypeByName(nameof(IFirstInterface))));
            var mixin = Substitute.For<MixinReference>();
            mixin.Class.Returns(@class);

            // act
            var addInterfaceWriter = new AddInterfacesToChildSyntaxWriter(mixin, sourceCode.Semantic, startPos);
            var newChildClass = (ClassDeclarationSyntax)addInterfaceWriter.Visit(childClass);
            var baseList = newChildClass.BaseList.Types;
            // assert: child class should have the mixin as interface
            Assert.AreEqual(1, baseList.Count);
            Assert.IsNotNull(baseList.Single(x => x.TypeName() == "MixinRefactoring.Test.IFirstInterface"));
        }
Пример #28
0
 public void Setup()
 {
     _sourceCode = new SourceCode(Files.Interface);
     _factory = new ClassFactory(_sourceCode.Semantic);
 }
Пример #29
0
        public void ChildWithAbstractProperty_Include_AbstractPropertyOverridden()
        {
            // we need Person file and NotCompilable because
            // the base class is defined in Person file
            var sourceCode = new SourceCode(Files.Person, Files.NotCompilable, Files.Name);
            var personClass = sourceCode.Class("PersonFromAbstractName");
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // there should be two methods, from base mixin and derived mixin
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count());
            // only one method from the mixin should be implemented, the other one
            // is alredy implemented by childs base
            Assert.AreEqual(1, mixer.PropertiesToImplement.Count(x => x.Name == "Name"));
            Assert.IsTrue(mixer.PropertiesToImplement.Single().IsOverride);
        }
Пример #30
0
        public void ChildWithOverrideProperty_Include_PropertyOverrideNotCreated()
        {
            var sourceCode = new SourceCode(Files.Person, Files.Name);
            var personClass = sourceCode.Class(nameof(PersonWithOverriddenProperty));
            var mixinReference = personClass.FindMixinReference("_name");
            var semanticModel = sourceCode.Semantic;

            var mixin = new MixinReferenceFactory(semanticModel).Create(mixinReference);
            var child = new ClassFactory(semanticModel).Create(personClass);

            var mixer = new Mixer();
            mixer.IncludeMixinInChild(mixin, child);

            // no property to override because child overrides it already
            Assert.AreEqual(0, mixer.PropertiesToImplement.Count());
        }