Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

@manofstick
Copy link
Contributor

This is a prelude to an alternative Lazy implementation in a PR at
dotnet/coreclr#8963

This is a prelude to an alternative Lazy implementation in a PR at
dotnet/coreclr#8963
/// the original suite as well as this one. These tests were written with the express purpose of testing
/// that the implementation conforms to the existing implementation, rather than to specification.
/// The two reasons obviously have major overlap (obviously), but leads to the flavour of this suite
/// being rather dense and repeditive, which for regression I feel is suitable.
Copy link
Member

@stephentoub stephentoub Jan 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I appreciate the sentiment here, in a month or a year or whatever, it's not really going to matter that the implementation changed: then we really just want a suite that validates Lazy's behavior. We should avoid duplication and have a single suite that validates the behavior. Let's just add tests for things that aren't currently being exercised.

@stephentoub
Copy link
Member

@dotnet-bot test this please

Copy link
Contributor

@AlexGhiondea AlexGhiondea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@manofstick
Copy link
Contributor Author

manofstick commented Feb 2, 2017

@AlexGhiondea

I will probably bash this code a little bit; so don't pull out in yet. I have just been a bit busy, sorry.

Just looking at consolidating some of the tests as per @stephentoub comments.

Hopefully sometime over this coming weekend.

@AlexGhiondea
Copy link
Contributor

@manofstick sounds good! Thanks for working on this!

@manofstick
Copy link
Contributor Author

@AlexGhiondea

OK; I think I'm good now.

Lazy<string> lazy = null;
lazy = new Lazy<string>(() => x++ < 5 ? lazy.Value : "Test", true);
[Fact]
public static void Ctor_ExceptionRecovery()
Copy link
Member

@stephentoub stephentoub Feb 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we try to use [Theory] with [MemberData] for things like this. Your previous case made sense not to use that, as it would have been difficult/cumbersome to handle needing to construct the lazy instances with a delegate that referred back to the same instance. In this case, though, it'd be pretty straightforward to do it that way, e.g.

public static IEnumerable<object[]> Ctor_ExceptionRecovery_MemberData()
{
    yield return new object[] { new Lazy<InitiallyExceptionThrowingCtor>(), 5 };
    yield return new object[] { new Lazy<InitiallyExceptionThrowingCtor>(true), 5 };
    ... // etc.
}

[Theory]
[MemberData(nameof(Ctor_ExceptionRecovery_MemberData))]
public static void Ctor_ExceptionRecovery(Lazy<InitiallyExceptionThrowingCtor> lazy, int? expected)
{
    ... // same body of Ctor_ExceptionRecovery_Impl test you currently have
}

That helps in a variety of ways, e.g. having xunit run each test case as its own test such that one failing doesn't cause the rest to fail, a description from xunit about exactly which case failed, etc., plus consistency with how we're trying to do these across corefx (there are a bunch of tests across corefx we haven't yet converted to that style, that we just ported as is from the internal tests used for desktop, but for all new ones we write we're trying to follow that style).

[Fact]
public static void CheckExceptions()
{
CheckException(typeof(MyException), new Lazy<int>(() => { throw new MyException(99); }));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't Assert.Throws<MyException> be used instead of this custom CheckException method?

{
Assert.Same(first, thrown2);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be better as something like:

private static void AssertIdempotentException<T>(Lazy<T> x)
{
    MyException e = Assert.Throws<MyException>(() => x.Value);
    Assert.Same(e, Assert.Throws<MyException>(() => x.Value));
]

In addition to being more concise, it also ensure that the second call to Value throws (the existing version will still succeed if the second call doesn't throw).

Assert.NotNull(second);

Assert.NotEqual(first, second);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can similarly be condensed, and just use Assert.NotSame instead of Assert.Same.

SameException(new Lazy<ExceptionInCtor>(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None));

DifferentException(new Lazy<ExceptionInCtor>(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly));
}
Copy link
Member

@stephentoub stephentoub Feb 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another case where a [Theory] would be good (or, actually, two, one for the same case and one for the different case... effectively the assert methods I previously described become the [Theory], with a separate MemberData supplying the values).

}

[Fact]
static void Serialization_ValueType()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this run if it's not public?

}

[Fact]
static void Serialization_RefType()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this run if it's not public?

var fortytwo = (Lazy<int>)formatter.Deserialize(stream);
Assert.True(fortytwo.IsValueCreated);
Assert.Equal(fortytwo.Value, 42);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a small helper for this in:
https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Runtime/Serialization/Formatters/BinaryFormatterHelpers.cs
With that this would become something like:

[Fact]
public static void Serialization_Int32_Roundtrips()
{
    Lazy<int> clone = BinaryFormatterHelpers.Clone(new Lazy<int>(() => 42));
    Assert.True(clone.IsValueCreated);
    Assert.Equal(42, clone.Value);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh, running out of time and for some reason this just isn't working... I can see it used in ModuleTests.cs and PointerTests.cs, and I can see in the project file that there is a link to BinaryFormatterHelper.cs, but for some reason it just isn't being picked up; I'm just not seeing the System.Runtime.Serialization.Formatters.Tests namespace at all, and my time is running out, so I've left this as it originally was (baring the public change)


var fortytwo = (Lazy<string>)formatter.Deserialize(stream);
Assert.True(fortytwo.IsValueCreated);
Assert.Equal(fortytwo.Value, "42");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

@stephentoub
Copy link
Member

@manofstick, thank you for adding these (and addressing my previous comments)! I've left a few more comments on things I think it would be good to address.

@manofstick
Copy link
Contributor Author

@stephentoub

OK modified to use the Theory attribute (and other changes you had mentioned). Theory didn't seem to work with generic arguments, so had to duplicate some of the code with type specific methods; not sure if it ends up clearer than the original (But I'm not a huge fan of attributes so maybe just my personal preference!)

@danmoseley
Copy link
Member

@stephentoub is this addressed to your satisfaction?

@danmoseley
Copy link
Member

@dotnet-bot test this please (logs gone)

using System.Threading;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing a using System.Runtime.Serialization.Formatters.Tests;... I believe that's the cause of the CI failures.

private static void Value_Invalid_Impl<T>(ref Lazy<T> x, Lazy<T> lazy)
{
x = lazy;
Assert.Throws<InvalidOperationException>(() => { var dummy = lazy.Value; });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the () => { var dummy = lazy.Value; } can I believe be simplified to just () => lazy.Value

public static void Ctor_ExceptionRecovery(Lazy<InitiallyExceptionThrowingCtor> lazy, int? expected)
{
InitiallyExceptionThrowingCtor.counter = 0;
var result = default(InitiallyExceptionThrowingCtor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: InitialiallyExceptionthrowingCtor result = null;

try { result = lazy.Value; } catch (Exception) { }
}
if (expected == null)
Assert.Null(result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null doesn't appear to ever be expected, is it?

private static void Value_ExceptionRecovery_IntImpl(Lazy<int> lazy, ref int counter, int expected)
{
counter = 0;
var result = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: var => int

if (expected == null)
Assert.Null(result);
else
Assert.Equal(result, expected);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this could just be Assert.Equal(expected, result) rather than special-casing expected == null... if expected is null, we expect result to be null, so Assert.Equal will work fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that expected should be the first argument to Equal, here and elsewhere

[Fact]
public static void Value_ExceptionRecovery()
{
var counter = default(int); // set in test function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: int counter = 0;

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding all of these. A few comments, but otherwise LGTM.

@stephentoub
Copy link
Member

Thanks!

@stephentoub stephentoub merged commit 029f4c4 into dotnet:master Feb 19, 2017
@karelz karelz modified the milestone: 2.0.0 Feb 22, 2017
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* System.Lazy regression tests

This is a prelude to an alternative Lazy implementation in a PR at
dotnet/coreclr#8963


Commit migrated from dotnet/corefx@029f4c4
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants