Coder Social home page Coder Social logo

stateprinter's Introduction

StatePrinter

Build status Nuget Nuget Nuget Coverage Status License Stats Stats

Join the chat at https://gitter.im/kbilsted/StatePrinter

THIS PROJECT IS BEING SUPERSEDED BY ReassureTest! GO TO https://github.com/kbilsted/ReassureTest.Net




What is Stateprinter

A simple framework for automating aspects of implementing ToString()-methods, unit testing, and debugging. Speed is achieved through run-time code generation and caching.

Why you should take StatePrinter for a spin

  • No more manual ToString() - it is much easier to write robust and self-sufficient ToString() methods. Seamless integration into a code-base with manually implemented ToString-methods.
  • No more manual writing/updating Asserts - both for new tests and when the code changes, all tests can automatically be corrected.
  • No more screens full of asserts. Especially testing against object-graphs is a bliss.
  • Very configurable and extensible.
  • It is part of the back-end engine of other projects

How do I get started

The documentation is split into

and

and

Where can I get it?

Install Stateprinter from the package manager console:

PM> Install-Package StatePrinter

And for pre-release versions

PM> Install-Package StatePrinter -Pre

How can I get help?

For quick questions, Stack Overflow is your best bet. For harder questions, bugs, issues or feature requests, create a GitHub Issue (and let's chat).

How can I help out

Everyone is encouraged to help improve this project. Here are a few ways you can help:

  • Blog about your experinces with the tool. We highly need publicity. I'll gladly link from here to your blog.
  • Report bugs
  • Fix issues and submit pull requests
  • Write, clarify, or fix the documentation
  • Suggest or add new features

StatePrinter has been awarded a ReSharper group license, to share among all active contributers.

Versioning

Stateprinter is maintained under the Semantic Versioning guidelines as much as possible. Releases will be numbered with the following format:

<major>.<minor>.<build>

and constructed with the following guidelines:

  • Breaking backward compatibility bumps the major
  • New additions without breaking backward compatibility bumps the minor
  • Bug fixes and misc changes increase the build number

For more information on SemVer, please visit http://semver.org/.

History

Version History: http://github.com/kbilsted/StatePrinter/blob/master/CHANGELOG.md

This file describes the latest pushed changes. For documentation of earlier releases see: 1.0.6, 1.0.5, 1.0.4

Upgrading from v1.xx to v2.0.x should be a matter of configuring the Configuration.LegacyBehaviour

Upgrading from v2.0 to v2.1 simply follow the documentation in the obsolete attributes.

Requirements

Requires .NET 3.5 or newer.

License

Stateprinter is under the Apache License 2.0, meaning that you can freely use this in other open source or commercial products. If you use it for commercial products please have the courtesy to leave me an email with a 'thank you'.

THIS PROJECT IS BEING SUPERSEDED BY ReassureTest! GO TO https://github.com/kbilsted/ReassureTest.Net

Have fun!

Kasper B. Graversen

stateprinter's People

Contributors

addamichal avatar ajryan avatar aloisdg avatar daniel15 avatar gitter-badger avatar janusschmidt avatar jawn avatar kbilsted avatar kristianhald avatar pberggreen avatar romkatv avatar sjdirect avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stateprinter's Issues

Ensure correct Json format

The JsonSerializer can be used for generating json text from an object graph (with no cycles). Possibly this could be used as a reference solution and compared against stateprinter's way of generating json

Support printing database state

As of now, Stateprinter has focused on printing state from memory. There is nothing wrong with printing state read from a subset of a database. Eg.

printer.PrintTable("SELECT TOP y x,y,z FROM a WHERE b", "rows of a", conn)
printer.PrintTable(string sql, string rootname, Connection conn)

or

printer.PrintTable(IQueryable<T> q, string rootname)

possibly for the method taking sql as an argument, we need an overload taking a transaction such that we can read data that is not yet committed (and might need to be rolled back, eg. in a unit test)

Debug assistance window

Implement a multi-panel wpf "editor" that supports xml-folding and raw text, maybe even show images produced by graphwiz.

the idea is to insert printer.Debug.PrintObject(o) and this editor will open, or if already open, will add a new pane. Thereby we enable better debugging sessions for programmers dealing with a lot of data.

this is advantageous over the normal profiler view in

  1. you can search the content of the panel
  2. you have several panels potentially, which show the development of state

I think its best not to use 3rd party plugins for this in order to keep dependencies at 0 for StatePrinter

Obsolete include projection

When #17 is completed,

  • deprecate include filtering and update documentation to use the new map functionality
  • document the map-functionality

note use the feature/mapprojection branch

Weird output of data structure

curly style output of

public class TagsCollection
{
    public Dictionary<string, List<string>> Pages = new Dictionary<string, List<string>>();

    public void Add(string tag, string url)
    {
        List<string> urls;
        if (!Pages.TryGetValue(tag, out urls))
            Pages.Add(tag, urls = new List<string>());
        urls.Add(url);
    }
}

becomes

var expected = @"new TagsCollection()
{
    Pages[""Design""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""SOLID""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[1] = ""BookReviews\Adaptive Code via CS.md""
    Pages[""Single_Responsibility_Principle""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""Design_Pattern""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""Decorator""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""Wrapper""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""Cache""] = new List<String>()
    Pages[0] = ""Articles\Design\MalleableCodeUsingDecorators.md""
    Pages[""Book_Review""] = new List<String>()
    Pages[0] = ""BookReviews\Adaptive Code via CS.md""
}";

Field harvester factory method

We need an easy way to create an anonymous field harvester. The configuration should have an AddHarvester taking two lambdas as argument which should create an instance of a new AnonymousFieldHarveater

Path-based references

The current method used for avoiding cycles and duplicate printing, using index-based references, is not serving us well in the use case of StatePrinter combined with ApprovalTests as a way of ensuring object state doesn't change over time. If one new reference is added or removed somewhere 'early' in the object, the indices of all following references are incremented, making it very difficult to tell what really changed. For example, if we have this printed object:

Root = new RootObject()
{
    _container = new Container(), ref: 1
    {
        _objects = new List<Object>()
        {
            [0] = new A(), ref: 0
            {
            }
        }
        _a = -> 0
    }
    _otherObject = new OtherObject()
    {
        _container = -> 1
    }
    [lots more objects with lots more references]
}

If the reference to the object A() is removed, all following reference indices will be decremented. When looking at the change to the object, there will be a diff for each line in the file that previously had a reference on it. For very large files (1000s of lines), it becomes tedious to spot the real change, especially if there are other real changes later in the file.

I propose a 'path-based' way of referencing instead. The above example would then look something like this:

Root = new RootObject()
{
    _container = new Container()
    {
        _objects = new List<Object>()
        {
            [0] = new A()
            {
            }
        }
        _a = -> Root._container._objects[0]
    }
    _otherObject = new OtherObject()
    {
        _container = -> Root._container
    }
    [lots more objects with lots more references]
}

With this approach, changes wouldn't ripple to unrelated objects like described above.

I'm not sure if it's better to do an absolute path from root (as shown above) or a relative path. Maybe that could be user-configurable. With relative paths, the above references could then look something like this._objects[0] and ^._container.

If I get the time, I might take a first stab at implementing this. I imagine it will require some fairly substantial changes in Introspector.

Tests don't run in Visual Studio 2017

When attempting to run the tests in VS 2017 (Enterprise v15.9.2) it gives the following error when attempting to run all tests.
As suggested, I upgraded the test project to Framework v4.0 and all tests could be run.

[15/01/2019 13:49:51 Informational] ------ Discover test started ------
[15/01/2019 13:49:51 Error] Microsoft.VisualStudio.TestPlatform.ObjectModel.TestPlatformException: Framework35 is not supported. For projects targeting .Net Framework 3.5, please use Framework40 to run tests in CLR 4.0 "compatibility mode".
   at Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers.TestRequestManager.UpdateRunSettingsIfRequired(String runsettingsXml, List`1 sources, String& updatedRunSettingsXml)
   at Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers.TestRequestManager.DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, ProtocolConfig protocolConfig)
   at Microsoft.VisualStudio.TestPlatform.Client.DesignMode.DesignModeClient.<>c__DisplayClass20_0.<StartDiscovery>b__0()
[15/01/2019 13:49:51 Informational] ========== Discover test finished: 0 found (0:00:00.3566916) ==========
[15/01/2019 13:49:57 Informational] ------ Run test started ------
[15/01/2019 13:49:57 Error] Microsoft.VisualStudio.TestPlatform.ObjectModel.TestPlatformException: Framework35 is not supported. For projects targeting .Net Framework 3.5, please use Framework40 to run tests in CLR 4.0 "compatibility mode".
   at Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers.TestRequestManager.UpdateRunSettingsIfRequired(String runsettingsXml, List`1 sources, String& updatedRunSettingsXml)
   at Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers.TestRequestManager.RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLauncher testHostLauncher, ITestRunEventsRegistrar testRunEventsRegistrar, ProtocolConfig protocolConfig)
   at Microsoft.VisualStudio.TestPlatform.Client.DesignMode.DesignModeClient.<>c__DisplayClass19_0.<StartTestRun>b__0()
[15/01/2019 13:49:57 Informational] ========== Run test finished: 0 run (0:00:00.026926) ==========

CultureInfo is not respected

On the master branch in the CultureTests.CultureDependentPrinting_us test, the test fails on my machine with the result:

String lengths are both 21. Strings differ at index 1.
Expected: "2/28/2010 10:10:59 PM"
But was:  "28-Feb-10 10:10:59 PM"

My machine uses the Thailand culture.

Support custom ordering of collections

Enhance the IntroSpector class to support configurable ordering of collections. The configuration should work in the same "stacking" manner as the FieldHarvesters.

Also a standard implementation for IEnumerable Where T : IComparable should be made.

proposal: Change minimum .net supported version

So the current min is .net 3.5. which was released ~11 years ago.

Perhaps the new min could be 4.5.2, released ~4 years ago ?

I know this is a breaking change, but people still using 3.5 can stay on the old nuget until they can move on to 4.5.2.

related to: #52

Rolling guid-ValueConverter

to simplify unit testing with data containing guids, we need to ensure the guid values are stable across executions.

Thus a valueconverter for guids. converting them into 000001, 000002, ... as they meet is needed. A dictionary should hold converted values to ensure the same guid printed multiple times is printed with its new value.

Get enspired from the existing GuidValueConverter

Also documentation on how to use it in unit testing is needed

Output valid C#

This would be so useful to me... if only it could output valid C# code! Currently, I have to print the object and then mess around with it to get it to compile. This would be such an awesome feature. Obviously cycles could not be supported.

make support for combinatorial input to tests

since we can autogenerate asserts, we should provide a helper architecture to provide combinatorial input to test methods, join their result and assert against that.

e.g. a method taking two bools as arguments, should get 4 inputs, each of which must be applied

but also composite types must be creatable in the same manner, with plugability such that the end user can specify how to create bespoke types. Eg a class Person with a first name, surname, zip code and address

maybe provide a testresultclass, that is more or less an array of strings which are stateprinted actual results.

Problem with rewriting expected values if value contains brackets.

Current version does not correctly rewrite expected value, if given value contains brackets.
Example:

string expected = @"new List<Int32>()
{
    [0] = 1
    [1] = 2
    [2] = 3
    [3] = 4
}";
TestHelper.Assert().PrintEquals(expected, actual);

I created a pull request with proposed fix: #49

Root name fixing

The way the root name is passed down to the introspector as a fieldname assumed that there would be a sane field to attach this name to. Im not convinced this is the case when the root object is a dictionary of simple types or an enumerable. eg. an empty one. how these are printed do not necesarily leave room for the field name.

maybe the root name should be applied explicitly after the introspection rather than pushing down the root name to the first field. This may break with existing token production.

Filtering in the debugger output

A filtering mechanism needs be implemented to reduce the amount of information displayed in the debugger window. Maybe a textbox for inputting xpath could be a solution

StatePrinter throws if GetEnumerator() throws (e.g. on default ImmutableArray)

StatePrinter version: 3.0.1

class Foo
{
  public readonly ImmutableArray<int> arr = default;
}

[TestMethod]
public void Test()
{
  var printer = new Stateprinter(ConfigurationHelper.GetStandardConfiguration());

  Console.WriteLine(printer.PrintObject(new Foo()));
}

Throws:

System.InvalidOperationException: This operation cannot be performed on a default instance of ImmutableArray<T>.  Consider initializing the array, or checking the ImmutableArray<T>.IsDefault property.
   at System.Collections.Immutable.ImmutableArray`1.ThrowInvalidOperationIfNotInitialized()
   at System.Collections.Immutable.ImmutableArray`1.System.Collections.IEnumerable.GetEnumerator()
   at StatePrinting.Introspection.IntroSpector.IntrospectIEnumerable(Object source, Field field)
   at StatePrinting.Introspection.IntroSpector.Introspect(Object source, Field field)
   at StatePrinting.Introspection.IntroSpector.IntrospectComplexType(Object source, Field field, Type sourceType)
   at StatePrinting.Introspection.IntroSpector.Introspect(Object source, Field field)
   at StatePrinting.Introspection.IntroSpector.PrintObject(Object objectToPrint, String rootname)
   at StatePrinting.Stateprinter.PrintObject(Object objectToPrint, String rootname)

Possible fixes (not mutually exclusive):

  • Catch exceptions thrown by GetEnumerator() (possibly slow)
  • Special-case known types like ImmutableArray<> having this behavior (in this case, check the IsDefault property)
  • Check all values of IEnumerable value types for equality to the default value (but their Equals implementation often throws too; would probably need an unsafe "raw" equality test)

Properties that throw exceptions are not handled

If PublicFieldsAndPropertiesHarvester is used, and a property access attempt throws an exception, the exception bubbles up to the top and cannot be handled, as in the code below.

It would be better to at least allow the user to have the exception returned as the value for that property instead.

System.Reflection.TargetInvocationException occurred
  HResult=-2146232828
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
       at StatePrinter.FieldHarvesters.HarvestHelper.<>c__DisplayClass9.<GetFieldsAndProperties>b__6(Object o)
       at StatePrinter.Introspection.IntroSpector.IntrospectComplexType(Object source, Field field, Type sourceType)
       at StatePrinter.Introspection.IntroSpector.Introspect(Object source, Field field)
       at StatePrinter.Introspection.IntroSpector.PrintObject(Object objectToPrint, String rootname)
       at StatePrinter.Stateprinter.PrintObject(Object objectToPrint, String rootname)
  InnerException: 
       HResult=-2146233088
       Message=An identifier field is not present in this artifact's field collection.
       Source=kCura.Relativity.Client
       StackTrace:
            at MyApplication.DTOs.Artifact.get_TextIdentifier()
       InnerException: 

caching the configuration

The configuration class needs a cache. construct the cache as a wrapper for the configuration caching the result of the wrapper. Eg, calls to TryGetValueConverter and TryGetFieldHarvester

Make error message configurable upon assertion failiure

Currently, the assert error message is hard-coded. We need to introduce an abstraction that given the "new" and "old" values used in the assert along with the message provided in the assert and the escaped "new suggested value" for the assert-rewrite

e.g. something

string CreateAssertMessage(
  string actual, 
  string oldExpected, 
  string escapedNewExpected)

and provide a default behaviour that shows the full old and new values for the assert

The CreateAssertMessage should be configurable through the Configuration class.

Ambigous constructors prevent StatePrinter from being used by VB.Net

StatePrinter has two constructors: Stateprinter and StatePrinter (deprecated)

Believe it or not (took me a while), when viewed from VB.Net, these are ambiguous because VB is case insensitive.

AFAICS, this completely prevents SP from being used from VB without the developer writing her own C# wrapper class to hide the original SP constructors.

Please see my question at StackOverflow which gives a bit more detail: http://stackoverflow.com/questions/35092412/using-stateprinter-from-vb-rather-than-c-sharp-to-implement-tostring

The simplest solution would be to drop the old constructor altogether and beware case-only differences in the future. If you can't do that for backward compatibility reasons, perhaps you could cut a VB-only, futures-only version.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.