Proposal for GenerationDepthBehavior.
See original GitHub issueHere is a generation Depth limiter behavior proposal.
fixture.Behaviors.Add(new GenerationDepthBehavior(2));
Had to re-implement ComposeIfMultiple for test because it’s internal.
public class GenerationDepthBehavior : ISpecimenBuilderTransformation
{
private const int DefaultGenerationDepth = 1;
private readonly int generationDepth;
public GenerationDepthBehavior() : this(DefaultGenerationDepth)
{
}
public GenerationDepthBehavior(int generationDepth)
{
if (generationDepth < 1)
throw new ArgumentOutOfRangeException(nameof(generationDepth), "Generation depth must be greater than 0.");
this.generationDepth = generationDepth;
}
public ISpecimenBuilderNode Transform(ISpecimenBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
return new GenerationDepthGuard(builder, new GenerationDepthHandler(), this.generationDepth);
}
}
public interface IGenerationDepthHandler
{
object HandleGenerationDepthLimitRequest(object request, IEnumerable<object> recordedRequests, int depth);
}
public class DepthSeededRequest : SeededRequest
{
public int Depth { get; }
public DepthSeededRequest(object request, object seed, int depth) : base(request, seed)
{
Depth = depth;
}
}
public class GenerationDepthGuard : ISpecimenBuilderNode
{
private readonly ThreadLocal<Stack<DepthSeededRequest>> requestsByThread
= new ThreadLocal<Stack<DepthSeededRequest>>(() => new Stack<DepthSeededRequest>());
private Stack<DepthSeededRequest> GetMonitoredRequestsForCurrentThread() => this.requestsByThread.Value;
public GenerationDepthGuard(ISpecimenBuilder builder)
: this(builder, EqualityComparer<object>.Default)
{
}
public GenerationDepthGuard(
ISpecimenBuilder builder,
IGenerationDepthHandler depthHandler)
: this(
builder,
depthHandler,
EqualityComparer<object>.Default,
1)
{
}
public GenerationDepthGuard(
ISpecimenBuilder builder,
IGenerationDepthHandler depthHandler,
int generationDepth)
: this(
builder,
depthHandler,
EqualityComparer<object>.Default,
generationDepth)
{
}
public GenerationDepthGuard(ISpecimenBuilder builder, IEqualityComparer comparer)
{
this.Builder = builder ?? throw new ArgumentNullException(nameof(builder));
this.Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
this.GenerationDepth = 1;
}
public GenerationDepthGuard(
ISpecimenBuilder builder,
IGenerationDepthHandler depthHandler,
IEqualityComparer comparer)
: this(
builder,
depthHandler,
comparer,
1)
{
}
public GenerationDepthGuard(
ISpecimenBuilder builder,
IGenerationDepthHandler depthHandler,
IEqualityComparer comparer,
int generationDepth)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
if (depthHandler == null) throw new ArgumentNullException(nameof(depthHandler));
if (comparer == null) throw new ArgumentNullException(nameof(comparer));
if (generationDepth < 1)
throw new ArgumentOutOfRangeException(nameof(generationDepth), "Generation depth must be greater than 0.");
this.Builder = builder;
this.GenerationDepthHandler = depthHandler;
this.Comparer = comparer;
this.GenerationDepth = generationDepth;
}
public ISpecimenBuilder Builder { get; }
public IGenerationDepthHandler GenerationDepthHandler { get; }
public int GenerationDepth { get; }
public int CurrentDepth { get; }
public IEqualityComparer Comparer { get; }
protected IEnumerable RecordedRequests => this.GetMonitoredRequestsForCurrentThread();
public virtual object HandleGenerationDepthLimitRequest(object request, int currentDepth)
{
return this.GenerationDepthHandler.HandleGenerationDepthLimitRequest(
request,
this.GetMonitoredRequestsForCurrentThread(), currentDepth);
}
public object Create(object request, ISpecimenContext context)
{
if (request is SeededRequest)
{
int currentDepth = -1;
var requestsForCurrentThread = this.GetMonitoredRequestsForCurrentThread();
if (requestsForCurrentThread.Count > 0)
{
currentDepth = requestsForCurrentThread.Max(x => x.Depth) + 1;
}
DepthSeededRequest depthRequest = new DepthSeededRequest(((SeededRequest)request).Request, ((SeededRequest)request).Seed, currentDepth);
if (depthRequest.Depth >= this.GenerationDepth)
{
return HandleGenerationDepthLimitRequest(request, depthRequest.Depth);
}
requestsForCurrentThread.Push(depthRequest);
try
{
return this.Builder.Create(request, context);
}
finally
{
requestsForCurrentThread.Pop();
}
}
else
{
return this.Builder.Create(request, context);
}
}
public virtual ISpecimenBuilderNode Compose(
IEnumerable<ISpecimenBuilder> builders)
{
var composedBuilder = ComposeIfMultiple(
builders);
return new GenerationDepthGuard(
composedBuilder,
this.GenerationDepthHandler,
this.Comparer,
this.GenerationDepth);
}
internal static ISpecimenBuilder ComposeIfMultiple(IEnumerable<ISpecimenBuilder> builders)
{
ISpecimenBuilder singleItem = null;
List<ISpecimenBuilder> multipleItems = null;
bool hasItems = false;
using (var enumerator = builders.GetEnumerator())
{
if (enumerator.MoveNext())
{
singleItem = enumerator.Current;
hasItems = true;
while (enumerator.MoveNext())
{
if (multipleItems == null)
{
multipleItems = new List<ISpecimenBuilder> { singleItem };
}
multipleItems.Add(enumerator.Current);
}
}
}
if (!hasItems)
{
return new CompositeSpecimenBuilder();
}
if (multipleItems == null)
{
return singleItem;
}
return new CompositeSpecimenBuilder(multipleItems);
}
public virtual IEnumerator<ISpecimenBuilder> GetEnumerator()
{
yield return this.Builder;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class GenerationDepthHandler : IGenerationDepthHandler
{
public object HandleGenerationDepthLimitRequest(
object request,
IEnumerable<object> recordedRequests, int depth)
{
return new OmitSpecimen();
}
}
Issue Analytics
- State:
- Created 5 years ago
- Comments:13 (7 by maintainers)
Top Results From Across the Web
Developers - Proposal for GenerationDepthBehavior. -
Coming soon: A brand new website interface for an even better experience!
Read more >Object Proposal Generation
Object proposal generation is a preprocessing technique that has been widely used in current object detection pipelines to guide the search of objects...
Read more >Temporal Action Proposal Generation with Transformers
To capture the dependencies at different levels of granularity, this paper intuitively presents a unified temporal action proposal generation ...
Read more >A Hybrid Approach for Object Proposal Generation
This paper presents an efficient new hybrid object proposal method, which gets the initial proposal by computing multiple hierarchical ...
Read more >Generating Object Proposals | pdollar - WordPress.com
Each generated foreground mask serves as an object proposal, the proposals are ranked according to a learned scoring function. The algorithm is ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@malylemire1 Would you be fine if we postpone this for now and implement it later only if we see a lot of requests for this feature?
I’m sorry we cannot include every desired feature to the core 😟 It’s a bit hard to keep the balance between the provided feature and and the amount of code we maintain here. It looks like it will not be a big problem for you to implement this ad-hoc feature in your solution, so you are not blocked.
Thanks again for your proposal!
Its sad that this has not been built into the core. I have the exact same problem and have to use the workaround for now.