~divmod-dev/divmod.org/uneditable-contact-type-2513

« back to all changes in this revision

Viewing changes to Mantissa/xmantissa/test/test_people.py

  • Committer: moe
  • Date: 2008-01-17 15:03:33 UTC
  • Revision ID: svn-v4:866e43f7-fbfc-0310-8f2a-ec88d1da2979:trunk:14761
merge people-tags-2446-3.  introduces an API for filtering lists of people, and some UI for doing this with your address book.  author: moe, reviewer: glyph.  closes #2446

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
from epsilon import extime
24
24
from epsilon.extime import Time
25
25
from epsilon.structlike import record
 
26
from epsilon.hotfix import require
 
27
 
 
28
require('twisted', 'trial_assertwarns')
26
29
 
27
30
from axiom.store import Store, AtomicFile
28
 
from axiom.dependency import installOn, installedOn
 
31
from axiom.dependency import installOn
29
32
from axiom.item import Item
30
 
from axiom.attributes import inmemory, text
 
33
from axiom.attributes import inmemory, text, AND
31
34
from axiom.errors import DeletionDisallowed
 
35
from axiom import tags
32
36
 
33
37
from axiom.userbase import LoginSystem
34
38
 
48
52
    _stringifyKeys, makeThumbnail, _descriptiveIdentifier,
49
53
    ReadOnlyContactInfoView, PersonSummaryView, MugshotUploadForm,
50
54
    ORGANIZER_VIEW_STATES, MugshotResource, Notes, NotesContactType,
51
 
    ReadOnlyNotesView, ContactGroup)
 
55
    ReadOnlyNotesView, ContactGroup, AllPeopleFilter, VIPPeopleFilter,
 
56
    TaggedPeopleFilter)
52
57
 
53
58
from xmantissa.webapp import PrivateApplication
54
59
from xmantissa.liveform import (
56
61
    ListChanges, CreateObject, EditObject, FormParameter, ChoiceParameter,
57
62
    TEXTAREA_INPUT)
58
63
from xmantissa.ixmantissa import (
59
 
    IOrganizerPlugin, IContactType, IWebTranslator, IPersonFragment)
 
64
    IOrganizerPlugin, IContactType, IWebTranslator, IPersonFragment,
 
65
    IPeopleFilter)
60
66
from xmantissa.signup import UserInfo
 
67
from xmantissa.test.peopleutil import PeopleFilterTestMixin
61
68
 
62
69
 
63
70
# the number of non-plugin IContactType implementations provided by Mantissa.
64
71
builtinContactTypeCount = 5
 
72
# the number of non-plugin IPeopleFilter implementations provided by Mantissa
 
73
builtinPeopleFilterCount = 2
 
74
 
 
75
 
 
76
 
 
77
class AllPeopleFilterTests(PeopleFilterTestMixin, unittest.TestCase):
 
78
    """
 
79
    Tests for L{AllPeopleFilter}.
 
80
    """
 
81
    peopleFilterClass = AllPeopleFilter
 
82
    peopleFilterName = 'All'
 
83
 
 
84
 
 
85
    def test_queryComparison(self):
 
86
        """
 
87
        L{AllPeopleFilter}'s query comparison should include all people.
 
88
        """
 
89
        self.assertIdentical(
 
90
            self.peopleFilterClass().getPeopleQueryComparison(Store()),
 
91
            None)
 
92
 
 
93
 
 
94
 
 
95
class VIPPeopleFilterTests(PeopleFilterTestMixin, unittest.TestCase):
 
96
    """
 
97
    Tests for L{VIPPeopleFilter}.
 
98
    """
 
99
    peopleFilterClass = VIPPeopleFilter
 
100
    peopleFilterName = 'VIP'
 
101
 
 
102
 
 
103
    def test_queryComparison(self):
 
104
        """
 
105
        L{VIPPeopleFilter}'s query comparison should include only VIP people.
 
106
        """
 
107
        self.assertComparisonEquals(Person.vip == True)
 
108
 
 
109
 
 
110
 
 
111
class TaggedPeopleFilterTests(unittest.TestCase):
 
112
    """
 
113
    Tests for L{TaggedPeopleFilter}.
 
114
    """
 
115
    # this TestCase doesn't inherit from PeopleFilterTestMixin because of the
 
116
    # constructor argument and more complicated query.
 
117
 
 
118
    def test_implementsInterface(self):
 
119
        """
 
120
        L{TaggedPeopleFilter} should provide L{IPeopleFilter}.
 
121
        """
 
122
        self.assertTrue(
 
123
            IPeopleFilter.providedBy(TaggedPeopleFilter(u'tag')))
 
124
 
 
125
 
 
126
    def test_filterName(self):
 
127
        """
 
128
        Our L{TaggedPeopleFilter}'s I{filterName} should be the tag passed to
 
129
        its constructor.
 
130
        """
 
131
        self.assertEqual(
 
132
            TaggedPeopleFilter(u'test_filterName').filterName,
 
133
            u'test_filterName')
 
134
 
 
135
 
 
136
    def test_queryComparison(self):
 
137
        """
 
138
        L{TaggedPeopleFilter}'s query comparison should include only people
 
139
        who have had a certain tag applied to them.
 
140
        """
 
141
        actualComparison = TaggedPeopleFilter(
 
142
            u'test_queryOrdering').getPeopleQueryComparison(Store())
 
143
        expectedComparison = AND(
 
144
            tags.Tag.object == Person.storeID,
 
145
            tags.Tag.name == u'test_queryOrdering')
 
146
        # none of the Axiom query objects have meaningful equality
 
147
        # comparisons, but their string representations are just as good to
 
148
        # compare.
 
149
        self.assertEqual(
 
150
            str(actualComparison), str(expectedComparison))
65
151
 
66
152
 
67
153
 
392
478
 
393
479
    contactTypes = inmemory(
394
480
        doc="""
395
 
        A list of L{IContact} implementors to return from L{getContactTypes}.
 
481
        A list of L{IContactType} implementors to return from
 
482
        L{getContactTypes}.
 
483
        """)
 
484
 
 
485
    peopleFilters = inmemory(
 
486
        doc="""
 
487
        A list of L{IPeopleFilter} imlpementors to return from
 
488
        L{getPeopleFilters}.
396
489
        """)
397
490
 
398
491
    renamedPeople = inmemory(
472
565
        return self.contactTypes
473
566
 
474
567
 
 
568
    def getPeopleFilters(self):
 
569
        """
 
570
        Return L{peopleFilters}.
 
571
        """
 
572
        return self.peopleFilters
 
573
 
 
574
 
475
575
    def personalize(self, person):
476
576
        """
477
577
        Record a personalization attempt and return C{self.personalization}.
1515
1615
                name=name)
1516
1616
 
1517
1617
 
 
1618
    def test_getPeopleFilters(self):
 
1619
        """
 
1620
        L{Organizer.getPeopleFilters} should return an iterable of all of the
 
1621
        L{IPeopleFilter} plugins available in the store.
 
1622
        """
 
1623
        firstPeopleFilters = [object(), object()]
 
1624
        firstContactPowerup = StubOrganizerPlugin(
 
1625
            store=self.store, peopleFilters=firstPeopleFilters)
 
1626
        self.store.powerUp(
 
1627
            firstContactPowerup, IOrganizerPlugin, priority=1)
 
1628
 
 
1629
        secondPeopleFilters = [object()]
 
1630
        secondContactPowerup = StubOrganizerPlugin(
 
1631
            store=self.store, peopleFilters=secondPeopleFilters)
 
1632
        self.store.powerUp(
 
1633
            secondContactPowerup, IOrganizerPlugin, priority=0)
 
1634
 
 
1635
        self.assertEqual(
 
1636
            list(self.organizer.getPeopleFilters())[
 
1637
                builtinPeopleFilterCount:],
 
1638
            firstPeopleFilters + secondPeopleFilters)
 
1639
 
 
1640
 
 
1641
    def test_getPeopleFiltersTags(self):
 
1642
        """
 
1643
        L{Organizer.getPeopleFilters} should include one L{TaggedPeopleFilter}
 
1644
        for each tag which has been applied to a person.
 
1645
        """
 
1646
        personTags = list(u'xac')
 
1647
        catalog = tags.Catalog(store=self.store)
 
1648
        for personTag in personTags:
 
1649
            catalog.tag(Person(store=self.store), personTag)
 
1650
        peopleFilters = list(self.organizer.getPeopleFilters())[
 
1651
            builtinPeopleFilterCount:]
 
1652
        self.assertEqual(len(peopleFilters), len(personTags))
 
1653
        for (peopleFilter, personTag) in zip(peopleFilters, sorted(personTags)):
 
1654
            self.assertTrue(isinstance(peopleFilter, TaggedPeopleFilter))
 
1655
            self.assertEqual(peopleFilter.filterName, personTag)
 
1656
 
 
1657
 
1518
1658
    def test_createPerson(self):
1519
1659
        """
1520
1660
        L{Organizer.createPerson} should instantiate and return a L{Person} item
2138
2278
        self.assertEqual(tab.linkURL, None)
2139
2279
 
2140
2280
 
 
2281
    def test_getPeopleTags(self):
 
2282
        """
 
2283
        L{Organizer.getPeopleTags} should return a set containing each tag
 
2284
        which has been applied to a L{Person}.
 
2285
        """
 
2286
        alice = self.organizer.createPerson(u'Alice')
 
2287
        frank = self.organizer.createPerson(u'Frank')
 
2288
        catalog = tags.Catalog(store=self.store)
 
2289
        catalog.tag(alice, u'person')
 
2290
        catalog.tag(frank, u'person')
 
2291
        catalog.tag(alice, u'girl')
 
2292
        catalog.tag(frank, u'boy')
 
2293
        # tag the organizer for laughs
 
2294
        catalog.tag(self.organizer, u'organizer')
 
2295
        self.assertEqual(
 
2296
            self.organizer.getPeopleTags(),
 
2297
            set(('person', 'girl', 'boy')))
 
2298
 
 
2299
 
2141
2300
 
2142
2301
class POBox(Item):
2143
2302
    number = text()
2605
2764
                + [storeOwnerPersonName]))
2606
2765
 
2607
2766
 
 
2767
    def test_filterByFilter(self):
 
2768
        """
 
2769
        L{PersonScrollingFragment.filterByFilter} should change the scrolltable's
 
2770
        base constraint to the query comparison of the named filter.
 
2771
        """
 
2772
        queryComparison = object()
 
2773
        class MockPeopleFilter:
 
2774
            def getPeopleQueryComparison(_self, store):
 
2775
                self.assertIdentical(store, self.store)
 
2776
                return queryComparison
 
2777
        fragment = PersonScrollingFragment(
 
2778
            self.organizer,
 
2779
            object(),
 
2780
            Person.name,
 
2781
            StubTranslator(None, None))
 
2782
        fragment.filters = {
 
2783
            u'test_filterByFilter': MockPeopleFilter()}
 
2784
        filterByFilter = expose.get(fragment, 'filterByFilter')
 
2785
        filterByFilter(u'test_filterByFilter')
 
2786
        self.assertIdentical(
 
2787
            fragment.baseConstraint, queryComparison)
 
2788
 
 
2789
 
2608
2790
 
2609
2791
class StubOrganizer(object):
2610
2792
    """
2633
2815
 
2634
2816
    @ivar groupedReadOnlyViewPeople: A list of the arguments passed to
2635
2817
    L{groupReadOnlyViews}.
 
2818
 
 
2819
    @ivar peopleTags: The value to return from L{getPeopleTags}.
 
2820
    @type peopleTags: C{list}
 
2821
 
 
2822
    @ivar peopleFilters: The sequence to return from L{getPeopleFilters}.
 
2823
    @type peopleFilters: C{list}
2636
2824
    """
2637
2825
    _webTranslator = StubTranslator(None, None)
2638
2826
 
2639
2827
    def __init__(self, store=None, peoplePlugins=None, contactTypes=None,
2640
2828
            deletedPeople=None, editedPeople=None,
2641
 
            contactEditorialParameters=None, groupedReadOnlyViews=None):
 
2829
            contactEditorialParameters=None, groupedReadOnlyViews=None,
 
2830
            peopleTags=None, peopleFilters=None):
2642
2831
        self.store = store
2643
2832
        self.people = {}
2644
2833
        if peoplePlugins is None:
2653
2842
            contactEditorialParameters = []
2654
2843
        if groupedReadOnlyViews is None:
2655
2844
            groupedReadOnlyViews = {}
 
2845
        if peopleTags is None:
 
2846
            peopleTags = []
 
2847
        if peopleFilters is None:
 
2848
            peopleFilters = []
2656
2849
        self.peoplePluginList = peoplePlugins
2657
2850
        self.contactTypes = contactTypes
2658
2851
        self.deletedPeople = deletedPeople
2660
2853
        self.contactEditorialParameters = contactEditorialParameters
2661
2854
        self.groupedReadOnlyViews = groupedReadOnlyViews
2662
2855
        self.groupedReadOnlyViewPeople = []
 
2856
        self.peopleTags = peopleTags
 
2857
        self.peopleFilters = peopleFilters
2663
2858
 
2664
2859
 
2665
2860
    def peoplePlugins(self, person):
2690
2885
        return self.contactTypes
2691
2886
 
2692
2887
 
 
2888
    def getPeopleFilters(self):
 
2889
        """
 
2890
        Return L{peopleFilters}.
 
2891
        """
 
2892
        return self.peopleFilters
 
2893
 
 
2894
 
2693
2895
    def groupReadOnlyViews(self, person):
2694
2896
        """
2695
2897
        Return L{groupedReadOnlyViews}.
2702
2904
        return "/person/" + person.getDisplayName()
2703
2905
 
2704
2906
 
 
2907
    def getPeopleTags(self):
 
2908
        """
 
2909
        Return L{peopleTags}.
 
2910
        """
 
2911
        return self.peopleTags
 
2912
 
 
2913
 
2705
2914
 
2706
2915
class OrganizerFragmentTests(unittest.TestCase):
2707
2916
    """
2736
2945
 
2737
2946
    def test_peopleTable(self):
2738
2947
        """
2739
 
        L{OrganizerFragment.render_peopleTable} should return a
 
2948
        L{OrganizerFragment}'s I{peopleTable} renderer should return a
2740
2949
        L{PersonScrollingFragment}.
2741
2950
        """
2742
 
        request = FakeRequest(args={})
2743
 
        scroller = self.fragment.render_peopleTable(request, None)
 
2951
        peopleTableRenderer = renderer.get(self.fragment, 'peopleTable')
 
2952
        scroller = peopleTableRenderer(None, None)
2744
2953
        self.assertTrue(isinstance(scroller, PersonScrollingFragment))
2745
2954
 
2746
2955
 
 
2956
    def test_peopleFilters(self):
 
2957
        """
 
2958
        L{OrganizerFragment}'s I{peopleFilters} renderer should return an
 
2959
        instance of its tag's I{filter} pattern for each filter, except the
 
2960
        first, which should use the I{selected-filter} pattern.
 
2961
        """
 
2962
        filterNames = list('acyx')
 
2963
        peopleFilters = [record('filterName')(name) for name in filterNames]
 
2964
        self.organizer.peopleFilters = peopleFilters
 
2965
        peopleFiltersRenderer = renderer.get(self.fragment, 'peopleFilters')
 
2966
        tag = div[
 
2967
            div(usedpattern='filter', pattern='filter')[slot('name')],
 
2968
            div(usedpattern='selected-filter',
 
2969
                pattern='selected-filter')[slot('name')]]
 
2970
        patterns = list(peopleFiltersRenderer(None, tag))
 
2971
        self.assertEqual(len(patterns), len(peopleFilters))
 
2972
 
 
2973
        selectedPattern = patterns.pop(0)
 
2974
        selectedFilterName = filterNames.pop(0)
 
2975
        self.assertEqual(
 
2976
            selectedPattern.slotData, {'name': selectedFilterName})
 
2977
        self.assertEqual(
 
2978
            selectedPattern.attributes['usedpattern'], 'selected-filter')
 
2979
 
 
2980
        for (pattern, filterName) in zip(patterns, filterNames):
 
2981
            self.assertEqual(pattern.slotData, {'name': filterName})
 
2982
            self.assertEqual(pattern.attributes['usedpattern'], 'filter')
 
2983
 
 
2984
 
2747
2985
    def test_getAddPerson(self):
2748
2986
        """
2749
2987
        L{OrganizerFragment.getAddPerson} should return an