1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#import "ObjectTesting.h"
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSCache.h>
@interface TestObject : NSObject <NSDiscardableContent>
{
BOOL _discarded;
}
@end
@implementation TestObject
- (BOOL)beginContentAccess
{
return YES;
}
- (void)endContentAccess
{
}
- (void)discardContentIfPossible
{
_discarded = YES;
}
- (BOOL)isContentDiscarded
{
return _discarded;
}
@end
int main()
{
NSAutoreleasePool *arp = [NSAutoreleasePool new];
NSCache *cache = [[NSCache new] autorelease];
[cache setName: @"Foo"];
PASS_EQUAL(@"Foo", [cache name], "Name can be set an accessed");
[cache setCountLimit: 2];
PASS(2 == [cache countLimit], "Count limit can be set and accessed");
[cache setTotalCostLimit: 3];
PASS(3 == [cache totalCostLimit], "Total cost limit can be set and accessed");
[cache setObject: @"bar" forKey: @"foo"];
PASS_EQUAL(@"bar", [cache objectForKey: @"foo"],
"Cached object can be returned");
/*
* NOTE: The following to test sets currently won't work. The only available
* eviction strategy is to evict under the following conditions:
*
* - evictsObjectsWithDiscardedContent is set on the receiver
* - the cached object implements NSDiscardableContent
* - the content is actually discarded
*/
START_SET("count-based eviction")
testHopeful = YES;
/* Let's test count based eviction: We add two more items and expect the
* first one (foo) to be removed because the count limit is two
*/
[cache setObject: @"baz" forKey: @"bar"];
NSUInteger i = 0;
for (i = 0; i < 50; i++)
{
/* We need to heat this object in the cache so that the first one
* becomes elligible for eviction
*/
[cache objectForKey: @"bar"];
}
[cache setObject: @"frubble" forKey: @"baz"];
PASS_EQUAL(@"frubble", [cache objectForKey: @"baz"],
"LRU object retained on count overflow");
PASS_EQUAL(@"baz", [cache objectForKey: @"bar"],
"second object retained on count overflow");
PASS(nil == [cache objectForKey: @"foo"], "Oldest object evicted");
END_SET("count-based eviction")
[cache removeAllObjects];
START_SET("cost-based eviction")
testHopeful = YES;
[cache setObject: @"bar" forKey: @"foo" cost: 2];
// This should push out the previous object because the cumulative cost (4)
// exceeds the limit (3)
[cache setObject: @"baz" forKey: @"bar" cost: 2];
PASS_EQUAL(@"baz", [cache objectForKey: @"bar"],
"LRU object retained on cost overflow");
PASS(nil == [cache objectForKey: @"foo"], "Overflowing object evicted");
END_SET("cost-based eviction")
[cache removeAllObjects];
START_SET("eviction of discardable content")
cache = [[NSCache new] autorelease];
[cache setCountLimit: 1];
[cache setEvictsObjectsWithDiscardedContent: YES];
TestObject *a = [[TestObject new] autorelease];
TestObject *b = [[TestObject new] autorelease];
[cache setObject: a forKey: @"foo"];
[cache setObject: b forKey: @"bar"];
PASS_EQUAL(b, [cache objectForKey: @"bar"],
"LRU object retained on count overflow");
PASS(nil == [cache objectForKey: @"foo"],
"Overflowing object evicted on count overflow");
PASS([a isContentDiscarded],
"Cache did call -discardContentIfPossible on cached object");
[cache removeAllObjects];
[cache setCountLimit: 0];
[cache setTotalCostLimit: 3];
a = [[TestObject new] autorelease];
b = [[TestObject new] autorelease];
[cache setObject: a forKey: @"foo" cost: 2];
[cache setObject: b forKey: @"bar" cost: 2];
PASS_EQUAL(b, [cache objectForKey: @"bar"],
"LRU object retained on cost overflow");
PASS(nil == [cache objectForKey: @"foo"],
"Overflowing object evicted on cost overflow");
PASS([a isContentDiscarded],
"Cache did call -discardContentIfPossible on cached object");
END_SET("eviction of discardable content")
[arp release]; arp = nil;
return 0;
}
|