def test_getChangeUids_multi(self):
        yield self.insertTestData(self.change14_rows + self.change13_rows + [
            fakedb.User(uid=1, identifier="one"),
            fakedb.User(uid=2, identifier="two"),
            fakedb.User(uid=99, identifier="nooo"),
            fakedb.ChangeUser(changeid=14, uid=1),
            fakedb.ChangeUser(changeid=14, uid=2),
            fakedb.ChangeUser(changeid=13, uid=99),  # not selected
        ])
        res = yield self.db.changes.getChangeUids(14)

        self.assertEqual(sorted(res), [1, 2])
    def test_getChangeUids_found(self):
        yield self.insertTestData(self.change14_rows + [
            fakedb.SourceStamp(id=92),
            fakedb.User(uid=1),
            fakedb.ChangeUser(changeid=14, uid=1),
        ])
        res = yield self.db.changes.getChangeUids(14)

        self.assertEqual(res, [1])
class Change(unittest.TestCase, TestReactorMixin):

    change23_rows = [
        fakedb.Change(changeid=23, author="dustin", committer="dustin", comments="fix whitespace",
                      branch="warnerdb", revision="deadbeef",
                      when_timestamp=266738404, revlink='http://warner/0e92a098b',
                      category='devel', repository='git://warner', codebase='mainapp',
                      project='Buildbot'),

        fakedb.ChangeFile(changeid=23, filename='master/README.txt'),
        fakedb.ChangeFile(changeid=23, filename='worker/README.txt'),

        fakedb.ChangeProperty(changeid=23, property_name='notest',
                              property_value='["no","Change"]'),

        fakedb.ChangeUser(changeid=23, uid=27),
    ]

    def setUp(self):
        self.setUpTestReactor()
        self.master = fakemaster.make_master(self, wantDb=True)
        self.change23 = changes.Change(**dict(  # using **dict(..) forces kwargs
            category='devel',
            repository='git://warner',
            codebase='mainapp',
            who='dustin',
            committer='dustin',
            when=266738404,
            comments='fix whitespace',
            project='Buildbot',
            branch='warnerdb',
            revlink='http://warner/0e92a098b',
            properties={'notest': "no"},
            files=['master/README.txt', 'worker/README.txt'],
            revision='deadbeef'))
        self.change23.number = 23

        self.change24 = changes.Change(**dict(
            category='devel',
            repository='git://warner',
            codebase='mainapp',
            who='dustin',
            committer='dustin',
            when=266738405,
            comments='fix whitespace again',
            project='Buildbot',
            branch='warnerdb',
            revlink='http://warner/0e92a098c',
            properties={'notest': "no"},
            files=['master/README.txt', 'worker/README.txt'],
            revision='deadbeef'))
        self.change24.number = 24

        self.change25 = changes.Change(**dict(
            category='devel',
            repository='git://warner',
            codebase='mainapp',
            who='dustin',
            committer='dustin',
            when=266738406,
            comments='fix whitespace again',
            project='Buildbot',
            branch='warnerdb',
            revlink='http://warner/0e92a098d',
            properties={'notest': "no"},
            files=['master/README.txt', 'worker/README.txt'],
            revision='deadbeef'))
        self.change25.number = 25

    @defer.inlineCallbacks
    def test_fromChdict(self):
        # get a real honest-to-goodness chdict from the fake db
        yield self.master.db.insertTestData(self.change23_rows)
        chdict = yield self.master.db.changes.getChange(23)

        exp = self.change23
        got = yield changes.Change.fromChdict(self.master, chdict)

        # compare
        ok = True
        ok = ok and got.number == exp.number
        ok = ok and got.who == exp.who
        ok = ok and got.committer == exp.committer
        ok = ok and sorted(got.files) == sorted(exp.files)
        ok = ok and got.comments == exp.comments
        ok = ok and got.revision == exp.revision
        ok = ok and got.when == exp.when
        ok = ok and got.branch == exp.branch
        ok = ok and got.category == exp.category
        ok = ok and got.revlink == exp.revlink
        ok = ok and got.properties == exp.properties
        ok = ok and got.repository == exp.repository
        ok = ok and got.codebase == exp.codebase
        ok = ok and got.project == exp.project
        if not ok:
            def printable(c):
                return pprint.pformat(c.__dict__)
            self.fail("changes do not match; expected\n{}\ngot\n{}".format(printable(exp),
                                                                           printable(got)))

    def test_str(self):
        string = str(self.change23)
        self.assertTrue(re.match(r"Change\(.*\)", string), string)

    def test_asText(self):
        text = self.change23.asText()
        self.assertTrue(re.match(textwrap.dedent('''\
            Files:
             master/README.txt
             worker/README.txt
            On: git://warner
            For: Buildbot
            At: .*
            Changed By: dustin
            Committed By: dustin
            Comments: fix whitespaceProperties:.
              notest: no

            '''), text), text)

    def test_asDict(self):
        dict = self.change23.asDict()
        self.assertIn('1978', dict['at'])  # timezone-sensitive
        del dict['at']
        self.assertEqual(dict, {
            'branch': 'warnerdb',
            'category': 'devel',
            'codebase': 'mainapp',
            'comments': 'fix whitespace',
            'files': [{'name': 'master/README.txt'},
                      {'name': 'worker/README.txt'}],
            'number': 23,
            'project': 'Buildbot',
            'properties': [('notest', 'no', 'Change')],
            'repository': 'git://warner',
            'rev': 'deadbeef',
            'revision': 'deadbeef',
            'revlink': 'http://warner/0e92a098b',
            'when': 266738404,
            'who': 'dustin',
            'committer': 'dustin'})

    def test_getShortAuthor(self):
        self.assertEqual(self.change23.getShortAuthor(), 'dustin')

    def test_getTime(self):
        # careful, or timezones will hurt here
        self.assertIn('Jun 1978', self.change23.getTime())

    def test_getTimes(self):
        self.assertEqual(self.change23.getTimes(), (266738404, None))

    def test_getText(self):
        self.change23.who = 'nasty < nasty'  # test the html escaping (ugh!)
        self.assertEqual(self.change23.getText(), ['nasty &lt; nasty'])

    def test_getLogs(self):
        self.assertEqual(self.change23.getLogs(), {})

    def test_compare(self):
        self.assertEqual(self.change23, self.change23)
        self.assertNotEqual(self.change24, self.change23)
        self.assertGreater(self.change24, self.change23)
        self.assertGreaterEqual(self.change24, self.change23)
        self.assertGreaterEqual(self.change24, self.change24)
        self.assertLessEqual(self.change24, self.change24)
        self.assertLessEqual(self.change23, self.change24)
        self.assertLess(self.change23, self.change25)