Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added Tests/CFSet/TestInfo
Empty file.
98 changes: 98 additions & 0 deletions Tests/CFSet/create.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "CoreFoundation/CFSet.h"
#include "../CFTesting.h"

static void
countApplier (const void *value, void *context)
{
(void)value;
*((CFIndex *)context) += 1;
}

int main (void)
{
CFSetRef set;
CFSetRef copy;
CFSetRef other;
CFSetRef empty;
const void *values[3];
const void *out[3];
const void *found;
const void *otherValues[2];
CFIndex applied;
CFIndex i;
Boolean present;

values[0] = CFSTR("a");
values[1] = CFSTR("b");
values[2] = CFSTR("c");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can we also have a test for sets created from an array of values with duplicates / NULLs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Adding that test surfaced a bug, so I've left it out of this suite rather than assert the broken behaviour: CFSetCreate doesn't de-duplicate. From {a, b, a} it returns count 3, and CFSetGetValues then hands back a garbage third pointer (segfault). Root cause is GSHashTableCreate incrementing _count per array element with no existing-key check, so CFDictionaryCreate/CFBagCreate are affected too. I'll fix that in a separate PR and add the de-dup test (and the NULL-callbacks case) there.


set = CFSetCreate (NULL, values, 3, &kCFTypeSetCallBacks);
PASS_CF(set != NULL, "CFSet created.");

PASS_CF(CFSetGetTypeID () != 0, "CFSet type ID is not zero.");
PASS_CF(CFGetTypeID (set) == CFSetGetTypeID (),
"CFSet has the CFSet type ID.");

PASS_CF(CFSetGetCount (set) == 3, "CFSetGetCount returns the value count.");

PASS_CF(CFSetContainsValue (set, CFSTR("b")),
"CFSetContainsValue finds a present value.");
PASS_CF(!CFSetContainsValue (set, CFSTR("z")),
"CFSetContainsValue rejects an absent value.");

PASS_CF(CFSetGetCountOfValue (set, CFSTR("b")) == 1,
"CFSetGetCountOfValue returns 1 for a present value.");
PASS_CF(CFSetGetCountOfValue (set, CFSTR("z")) == 0,
"CFSetGetCountOfValue returns 0 for an absent value.");

found = CFSetGetValue (set, CFSTR("c"));
PASS_CFEQ(found, CFSTR("c"), "CFSetGetValue returns the stored value.");
PASS_CF(CFSetGetValue (set, CFSTR("z")) == NULL,
"CFSetGetValue returns NULL for an absent value.");

found = NULL;
present = CFSetGetValueIfPresent (set, CFSTR("a"), &found);
PASS_CF(present && found != NULL,
"CFSetGetValueIfPresent reports a present value.");
present = CFSetGetValueIfPresent (set, CFSTR("z"), &found);
PASS_CF(!present,
"CFSetGetValueIfPresent reports an absent value.");

CFSetGetValues (set, out);
for (i = 0; i < 3; i++)
PASS_CF(CFSetContainsValue (set, out[i]),
"CFSetGetValues returns stored values.");

/* CFSetApplyFunction must visit every value exactly once. */
applied = 0;
CFSetApplyFunction (set, countApplier, &applied);
PASS_CF(applied == 3, "CFSetApplyFunction visits every value.");

copy = CFSetCreateCopy (NULL, set);
PASS_CF(copy != NULL, "CFSetCreateCopy returns a set.");
PASS_CFEQ(copy, set, "A copy is equal to the original.");
PASS_CF(CFHash (copy) == CFHash (set),
"A copy hashes the same as the original.");
CFRelease (copy);

/* A set with different members is not equal. */
otherValues[0] = CFSTR("a");
otherValues[1] = CFSTR("x");
other = CFSetCreate (NULL, otherValues, 2, &kCFTypeSetCallBacks);
PASS_CFNEQ(other, set, "Sets with different members are not equal.");
CFRelease (other);

/* An empty set. */
empty = CFSetCreate (NULL, NULL, 0, &kCFTypeSetCallBacks);
PASS_CF(empty != NULL && CFSetGetCount (empty) == 0,
"An empty set has count 0.");
PASS_CF(!CFSetContainsValue (empty, CFSTR("a")),
"An empty set contains no value.");
PASS_CF(CFSetGetValue (empty, CFSTR("a")) == NULL,
"CFSetGetValue on an empty set returns NULL.");
CFRelease (empty);

CFRelease (set);

return 0;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Maybe also add a brief test for empty sets.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

59 changes: 59 additions & 0 deletions Tests/CFSet/mutable.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "CoreFoundation/CFSet.h"
#include "../CFTesting.h"

int main (void)
{
CFMutableSetRef set;
CFMutableSetRef copy;

set = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks);
PASS_CF(set != NULL, "CFMutableSet created.");
PASS_CF(CFSetGetCount (set) == 0, "A new mutable set is empty.");

CFSetAddValue (set, CFSTR("a"));
CFSetAddValue (set, CFSTR("b"));
PASS_CF(CFSetGetCount (set) == 2, "CFSetAddValue adds values.");

/* A set holds each value once: adding a present value is a no-op. */
CFSetAddValue (set, CFSTR("a"));
PASS_CF(CFSetGetCount (set) == 2,
"CFSetAddValue does not duplicate a present value.");

/* CFSetSetValue adds a value that is not yet present. */
CFSetSetValue (set, CFSTR("c"));
PASS_CF(CFSetGetCount (set) == 3 && CFSetContainsValue (set, CFSTR("c")),
"CFSetSetValue adds an absent value.");
CFSetSetValue (set, CFSTR("c"));
PASS_CF(CFSetGetCount (set) == 3,
"CFSetSetValue leaves an already-present value alone.");

/* CFSetReplaceValue only acts when the value is already present. */
CFSetReplaceValue (set, CFSTR("a"));
PASS_CF(CFSetGetCount (set) == 3 && CFSetContainsValue (set, CFSTR("a")),
"CFSetReplaceValue keeps a present value.");
CFSetReplaceValue (set, CFSTR("z"));
PASS_CF(CFSetGetCount (set) == 3 && !CFSetContainsValue (set, CFSTR("z")),
"CFSetReplaceValue ignores an absent value.");

copy = CFSetCreateMutableCopy (NULL, 0, set);
PASS_CF(copy != NULL, "CFSetCreateMutableCopy returns a set.");
PASS_CFEQ(copy, set, "A mutable copy is equal to the original.");
CFRelease (copy);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Also test whether removing an absent value is a no op.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.


CFSetRemoveValue (set, CFSTR("b"));
PASS_CF(CFSetGetCount (set) == 2, "CFSetRemoveValue removes a value.");
PASS_CF(!CFSetContainsValue (set, CFSTR("b")),
"A removed value is no longer present.");

CFSetRemoveValue (set, CFSTR("z"));
PASS_CF(CFSetGetCount (set) == 2,
"CFSetRemoveValue of an absent value is a no-op.");

CFSetRemoveAllValues (set);
PASS_CF(CFSetGetCount (set) == 0,
"CFSetRemoveAllValues empties the set.");

CFRelease (set);

return 0;
}
Loading