« first day (1014 days earlier)      last day (2166 days later) » 

12:01 AM
RELOAD!
[Hosch250/Rubberduck] 23 commits. 13723 additions. 11576 deletions.
[rubberduck-vba/Rubberduck] 4 commits. 2 opened issues. 3 closed issues. 8 issue comments. 7102 additions. 7056 deletions.
[VSDiagnostics/VSDiagnostics] 1 issue comment.
 
@IvenBach it's excellent news actually: it means you're learning!
 
Does this look legit?
    internal interface IReturnTypeConverter
    {
        object Value { get; set; }
        bool IsValid { get; }
    }

    internal class ValueTypeConverter<T> where T : struct, IReturnTypeConverter
    {
        public bool IsValid
        {
            get { return _value.HasValue; }
        }

        private T? _value;
        public object Value
        {
            get { return _value; }
            set { _value = (value is T) ? (T) Convert.ChangeType(value, typeof(T)) : null as T?; }
I need to accept input as object in the Fake's base class so I can expose a common IFake interface via COM, but since it can be passed a Variant from the calling code I need to verify that the return type of the faked VBA function matches.
That way I can just call Err.Raise from inside the fake and let the VBA error handler take over if there's a configuration error.
 
12:20 AM
@Comintern if IsValid has HasValue semantics, wouldn't it be better to name it HasValue?
Actually, why can't it just be a Nullable<T>?
(I can't see the "else" part of the ternary on my phone)
 
The goal was to cut down on the amount of validation code in the Returns setup functions.
@Mat'sMug null as T?;
 
Looks like you want a Nullable<T> to me.
 
^
int? == Nullable<int>
Oh wait, here's why - no COM-visible type can expose generics
 
^ The problem is that I need to test whether T is in fact a T. I basically need to validate that an object is a T
 
Hmm wait no, it's internal
But with a Nullable<T> that would be guaranteed
 
12:27 AM
Yeah, it's internal, but in order to expose a generic interface I have to accept all of the [in] parameters as object.
 
^ then you got it right
 
There are so many of these damned functions that I want to make it as easy as possible to extend the provider.
 
Makes sense
 
12:46 AM
So isvalid is more of a type check than a null check, since the wrapped value will be null if the types mismatch. gotcha. nevermind what I said earlier about hasvalue ;-)
 
@Mat'sMug Or I just wrote bad code in the first place. Hey I am learning!
Is it frowned upon to put in a function as a parameter to another function?
 
Does VBA support it?
That's a very functional thing to do.
 
Not at all. Except you can't (easily) do that in VBA
In C# you pass.a delegate
 
IE structureName = GetStructureName("S" & GetRowCountOfTable(isDataBodyRangeNothing))
 
Oh, the result of a function
 
12:51 AM
Oh, that's not a problem at all, unless it is a complicated call, in which case you usually create an intermediate variable.
 
Avoid doing that if the function has any chance of raising an error
 
Isn't that what I said? Cause that's what I thought I asked.
@Mat'sMug so do as @Hosch250 says?
 
It's mostly style & preference IMO, but because you can't break and inspect the result before entering the function (and often it's library code so you just can't), I tend to store the result locally so I can do that if I need to.
 
It really depends on the context.
 
^
@IvenBach you asked about passing a function as a parameter - in C# (and VB.NET), you can do exactly that - pass the function as a parameter.
 
12:56 AM
I didn't think it was taboo and wanted to make sure.
@Mat'sMug That would be a Delegate, correct?
 
@Mat'sMug It's a bloody pain to do so, though. It is much easier in F#.
@IvenBach Or a Func<T>.
 
DoSomething(() => 4);
 
Or, for a void, an Action.
@Mat'sMug It's a bit more of a pain to do DoSomething(DoSomethingElse) though.
 
DoSomething(GetRandomNumber);
 
At least, on the caller's side.
 
12:57 AM
how is typing the function's name a pain?
 
@Mat'sMug Yes. IsValid is basically to test that it wasn't passed a reference type or Nothing from VBA and that the return value can be cast to the correct type.
 
It's not too bad, though, but it isn't something that's done too commonly.
 
Too much food! Let me digest what I've already taken in.
 
The T? is just a convenient place to store both the value and the state.
 
@Mat'sMug I was thinking of delegates, not Funcs. I take that back.
 
12:58 AM
IMO the hard part is declaring the parameter
void DoSomething(Func<string, int> lookup)
even then..
Func and Action built-in delegates serve pretty much every common delegate signature
private delegate void DoSomething();
^ is plain silly given the Action delegate
 
@Mat'sMug That's what I was talking about. In F#, you just type the name, and the type system figures it out automatically.
 
that has other implications
 
It figures it out based on the usage.
It is a whole different way of thinking.
 
^
FP is to OOP such as OOP is to procedural code that's completely untrue
what I mean is that FP is a different paradigm
if you come from a procedural paradigm, OOP is a whole different way of thinking too
 
FP is to OOP such as an apple is an orange.
 
1:07 AM
@Mat'sMug My words did ask that by in my mind I was asking about the result of that function. Sorry.
 
@IvenBach it's ok - it didn't even occur to me that passing a function around was a possibility or even that it had uses, until I learned about delegates in .net
 
Way back in the day when I was dabbling in C, I thought function pointers were magic.
 
I'm so used to VBA that doing this Func1(Func2()) means pass the result of Func2 into Func1.
@Comintern Hint: They still are, just not to you.
 
@Mat'sMug IIRC, that comes from lambda calculus.
Instead of x being a value, it can be a value or a function, IIUC.
 
Duh checking: I shouldn't have to 'idiot proof it', just make reasonable enough assumptions?
 
1:17 AM
We have to idiot-proof RD.
 
lol
 
@IvenBach Depends what the use case is.
 
If I provide a unique name for a list and they change it to be a name that's already in the list should I check for it already existing?
 
Or a hashmap, really.
That's what a dictionary is for.
Things keep timing out on me :/
 
Let me rephrase.
 
1:19 AM
If your list can have multiple entries of an item, use a list and don't check. If it should have unique entries, use a hashmap.
 
OK, I think this is about as reasonably small as I can get the Fake implementation boilerplate:
    public class MsgBox : FakeBase
    {
        public MsgBox() { HookDelegate = new MessageBoxDelegate(MsgBoxCallback); }

        private readonly ValueTypeConverter<int> _converter = new ValueTypeConverter<int>();
        public override void Returns(object value)
        {
            _converter.Value = value;
            base.Returns(value);
        }

        [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
        private delegate int MessageBoxDelegate(string prompt, int buttons, string title, string helpfile, int context);
 
Hashmap?
 
Sometimes called a hashset.
 
@Hosch250 Unique entries are preferred. Checking it is.
 
@IvenBach Think Scripting.Dictionary with no values - only keys.
 
1:20 AM
Not sure what VBA calls it, or if it even has it.
 
@Comintern that's awesome
 
@Comintern So you only check the .exists portion? Nifty idea.
 
^
I use Dictionaries in VBA like that all the time.
 
can't Return be made Virtual? will all or most implementations need a converter?
 
That's spoonfeeding at it's finest! Use what they already know to teach them something new.
 
1:23 AM
@Mat'sMug Unfortunately, everything will need a converter. There's not really a clean way to accept untyped input (Variant) and enforce typed use over a generic interface.
I'm trying to make the VBA calling code easier to deal with.
 
What if it were public class MsgBox : FakeBase<IReturnTypeConverter>?
 
Oh, I like that idea.
 
abstract class FakeBase<TReturnTypeConverter> where TReturnTypeConverter : IReturnTypeConverter
 
so you can have a private readonly TReturnTypeConverter _converter in the base class
 
1:25 AM
The only problem is generic restrictions for intrinsic types.
 
@Hosch250 man, that's beautiful!!
 
The only way you can do that is with where T : struct
 
@Comintern I don't think it's going to be a problem
 
I think you're right.
 
1:27 AM
Oops, forgot to run the tests.
 
> public class MsgBox : FakeBase<IReturnTypeConverter>
^ I meant public class MsgBox : FakeBase<IReturnTypeConverter<int>>
 
[rubberduck-vba/Rubberduck] build for commit e57e6658 on unknown branch: AppVeyor build failed
BUILD FAILURE!
 
wait no!
it's COM visible is it?
if it is, you can't inherit a generic class
 
The class isn't exposed directly - only the interface.
 
@Hosch250 it should also show the encapsulated field, no?
@Comintern still could be a problem
I think
 
hmm
 
@Mat'sMug Sure.
 
[Hosch250/Rubberduck] Hosch250 pushed commit 1aba356e to EncapsulateFieldDialog: Remove a couple UI tests
 
perhaps it's worth trying
 
        private IFake RetrieveOrCreateFake(Type type)
        {
            if (!ActiveFakes.ContainsKey(type))
            {
                ActiveFakes.Add(type, (FakeBase)Activator.CreateInstance(type));
            }
            return ActiveFakes[type];
        }

        #region Function Overrides

        public IFake MsgBox { get { return RetrieveOrCreateFake(typeof(MsgBox)); } }
^^That's the only COM visible coclass.
 
1:29 AM
@Duga Yeah, mocking the WPF thing is a pain. I'll work on fixing that sometime.
 
nice
 
IFake and IFakesProvider should be the only ComVisible parts.
 
@Hosch250 what does it look like with the preview box expander collapsed?
 
Just collapsed.
It's just an expander.
 
the window, it resizes correctly?
 
1:31 AM
No, it doesn't resize at all.
The WPF stuff has no control over the window size.
 
[rubberduck-vba/Rubberduck] build for commit 1aba356e on unknown branch: AppVeyor build succeeded
 
so you collapse the expander and you get a huge blank area
 
Well, unless you want to resize the window yourself.
 
either drop the expander, or we need to figure out how to get the window to resize
 
shrug
It isn't hurting anything, but sure.
I'll need to do that on the reorder/remove ones too.
 
1:34 AM
The settings window was pretty easy to make resizable IIR.
 
@Mat'sMug @Comintern Success story, changed a big block of code into three separate subs that can call each other with arguments as needed, eliminated three error possibilities, and made my UI prettier. Thanks for all your patience. Still tons of work to do, but this is the first chunk that is 100% done and I understand it completely and it works.
 
@Comintern that's because the WPF control automatically resizes to fit its container
 
And yes, I'm still at work at 8:30, but I'm just trying to live up to your all's example haha
 
Yeah, most of the work was setting minimums.
 
we just toggle the window's height on expand/collapse, and WPF does the rest
 
1:35 AM
Thanks again :)
 
@puzzlepiece87 nice!
 
@Mat'sMug Well, there is one way to do this.
Fire an event when it is expanded/collapsed. We can use hard-coded values and set the height.
 
So, I'll do that.
 
thanks
 
1:37 AM
OK, one thing: should I use the actual field (along with any others on the line(s)), or should I build an "ideal" field.
Like:
var fieldAcessibility = TargetDeclaration.Accessibility == Accessibility.Implicit
    ? string.Empty
    : TargetDeclaration.Accessibility.ToString();
var field = $"{fieldAcessibility} {TargetDeclaration.IdentifierName} As {TargetDeclaration.AsTypeName}";
(I'd make the as part optional too.)
Or should I show the whole Dim foo As Integer, bar As String statement?
Or, to make it interesting...
Dim _
foo _
As _
Integer
 
fieldAccessibility would be rendered as Private if implicit, to be explicit/"ideal" ;-)
 
Well, I was showing it as close as possible to theirs without showing the whole thing.
Or, I could just do TargetDeclaration.Context.GetText().
For a Dim foo As Integer statement, that just shows the foo As Integer part.
 
Guard clause comprehension is making me refactor this code to be cleaner.
 
Because it doesn't know off-hand whether the Dim pertains to more than one.
 
@Hosch250 do whatever works - once the code in my fork is merged that code will need to be rewritten anyway
 
1:43 AM
OK, I'll just do the last option.
#KISS
 
    public interface IModuleRewriter
    {
        /// <summary>
        /// Rewrites the entire module / applies all changes.
        /// </summary>
        void Rewrite();

        /// <summary>
        /// Removes all tokens for specified <see cref="Declaration"/>. Use <see cref="Rewrite"/> method to apply changes.
        /// </summary>
        /// <param name="target">The <see cref="Declaration"/> to remove.</param>
        /// <remarks>Removes a line that would be left empty by the removal of the declaration.</remarks>
 
@Mat'sMug Actually, the previewer code shouldn't need to be...
 
@Hosch250 right
 
We still need a string for the previewer.
Oh wait, I think the refactoring makes the field private.
 
yeah. just make sure you have the previewer and the actual refactoring code generation in separate methods - they can both call the same code generation method(s) for now, but keep in mind that the actual token replacement will eventually happen with a _rewriter call
yep.
 
1:47 AM
So, I can just show Private {identifier} As {value}.
And I think it adds the type too.
 
or {Tokens.Private} {identifier} {Tokens.As} {value}
 
Meh, I'll hardcode it.
If it changes, RD is suddenly obsolete anyway.
 
so we should inline all Tokens usages?
 
Wouldn't hurt, but if you want the other, sure.
 
Heading home. Thanks for the help.
 
1:50 AM
np :)
@Hosch250 I'm torn on that one actually
@Comintern what do you think?
 
Eh, I'll just use the Tokens.
 
sure
I think it's a legit idea though
 
@Mat'sMug I'd get used to it.
^
 
Tokens is nothing but an abstraction around a bunch of specific string literals
it has no other purpose
 
Intellisense.
 
1:53 AM
^
 
You don't get that for string literals.
 
hmm, just for that, it's worth having.
use Tokens everywhere and you'll never make a typo in what you inject into the users' code
 
The "hit 2 keys then tab" is nice too.
 
^
well, except for Tokens.As
but, consistency
that said I'm sure I'm guilty of a ton of such string literals
@Hosch250 what do you think of the IModuleRewriter interface?
 
What interface?
 
1:56 AM
@Hosch250 my only feedback on your developer story is your professional smile at the top :)
 
@Mat'sMug Not much about the identifier reference bits.
 
WTH am I doing passing process addresses around? It's not like they're going to change a̶t̶ ̶r̶u̶n̶t̶i̶m̶e̶ ever.
 
You don't have any context around them--you'll just remove the name.
Bloody internet, it took me a good minute to send that.
It's not going to be much use except for rename.
But, that alone is probably enough reason to keep it.
 
@Hosch250 the caller has the context / is responsible for that knowledge
 
2:01 AM
@Mat'sMug Yeah, but you'll almost never call Remove(reference).
 
hmm that's right
 
I'd just leave the reference ones out.
If we need to remove a reference, we can call Remove(reference.Context).
If we eventually decide we need it, we can reconsider later.
Unless you already wrote it, in which case it won't hurt anything to leave it.
 
I need a void Remove(IToken token) I think
 
That makes more sense.
It is resizing sweetly.
 
awesome!
Rename is at the wrong abstraction level
    public interface IModuleRewriter
    {
        /// <summary>
        /// Rewrites the entire module / applies all changes.
        /// </summary>
        void Rewrite();

        /// <summary>
        /// Removes all tokens for specified <see cref="Declaration"/>. Use <see cref="Rewrite"/> method to apply changes.
        /// </summary>
        /// <param name="target">The <see cref="Declaration"/> to remove.</param>
        /// <remarks>Removes a line that would be left empty by the removal of the declaration.</remarks>
crap, I thought I updated the xml docs
 
2:06 AM
Do the xml docs compile into the tlb?
 
I don't think so
 
@Comintern Not as far as I know.
They compile into a different document in the bin folder.
 
That would be a sweet feature.
 
Bloody internet!
 
2:09 AM
    public void Remove(IToken target)
    {
        _rewriter.Delete(target);
    }
 
At least I can program offline...
@Mat'sMug @Comintern Why is it reloading the types every time? They used to be cached so they would only load once.
 
good question
 
That's a good question - I haven't looked at that in a while.
 
looks like something is clearing the declarations marked built-in
 
Did that come out because of the duplicated reference counts?
 
2:11 AM
IsBuiltIn needs a rename
@Comintern hmm that's a possibility
 
IsNativeLibrary?
 
@Comintern IsExternal
 
Makes sense. That's kind of backward, isn't it.
 
IsNotUserCode is more awkward I think ;-)
oh you mean invert the state?
IsUserCode would be the right thing to do
but...
 
2:15 AM
[rubberduck-vba/Rubberduck] build for commit bd5ee3e3 on unknown branch: AppVeyor build succeeded
 
That's a bitch of a refactoring to name it if we invert state.
 
IsNonUserCode?
 
@Duga @Mat'sMug Review/merge ready.
 
IsNamedWithADoubleNegative
2
 
2:16 AM
Just Extract Interface and Assigned ByVal Parameter before we can close the UI issue.
 
if (!declaration.IsNonUserCode)
hmm
 
Yeah, that reads awkwardly.
 
we could add a IsUserCode member that returns !IsBuiltIn
 
#HackTheName
 
and deprecate IsBuiltIn and slowly invert the logic call by call
 
2:18 AM
^
That sounds like a plan.
 
No, just kill it and do it all at once. It will become a huge mess if you try that.
@Mat'sMug That kind of code is ugly.
 
Do you want to do the next 5 merge commits?
 
lol
 
I can do it after I'm done with the UI's.
Just keep using it until I tell you no.
 
2:20 AM
TestEngine is bound singleton, isn't it?
 
hmm, it's bound by the default interface binding
    private void ApplyDefaultInterfacesConvention(IEnumerable<Assembly> assemblies)
    {
        Kernel.Bind(t => t.From(assemblies)
            .SelectAllClasses()
            // inspections & factories have their own binding rules
            .Where(type => type.Namespace != null
                        && !type.Namespace.StartsWith("Rubberduck.VBEditor.SafeComWrappers")
                        && !type.Name.Equals("SelectionChangeService")
                        && !type.Name.EndsWith("Factory") && !type.Name.EndsWith("ConfigProvider") && !type.GetInterfaces().Contains(typeof(IInspecti
InCallScope
 
GTG, dishes.
 
Hmmm...
 
Small load, BBL.
 
2:22 AM
OK, I can work with that.
 
Alright, this feels wrong - I inject an IFakesProvider into TestEngine, but then I have to up-cast it to a FakesProvider because the interface has to hide a ton of stuff from COM.
If I do a factory, it has to be a singleton to enforce that the FakesProvider is a singleton...
 
@Comintern rebind it in singleton scope?
 
The binding is easy. The issue is that I can't have it implement the interface it needs to provide as an internal dependency because - COM.
 
make a new interface?
 
2:31 AM
I'm thinking factory is cleaner.
 
class FakesProvider : IComFakeProvider, IFakeProvider
 
IIR, any interface I put on it will be accessible to VBA.
I could try to hide it, but it would be the same problem that the AssertClass has with IDisposable.
 
hmm
 
Except in this case, calling something like Rubberduck.FakesProvider[_StartTest] is pretty much time to restart the host.
 
@Comintern lol!
 
2:39 AM
WTH can't you just implement an internal interface member with an internal?
 
huh, that'd be quite nice actually
 
Assert.AreEqual failed. Expected:<Private bar As Boolean
Private Sub Foo()
End Sub>. Actual:<Private bar As Boolean
Private Sub Foo()
    End Sub>.

   at RubberduckTests.Refactoring.IntroduceFieldTests.IntroduceFieldRefactoring_NoFieldsInClass_Sub()
#SoClose
 
Better than my progress. I just had the most spectacular Excel crash I've ever witnessed.
 
I'm factoring out indentation from the test's expectations
and I'll make a separate test that fails if indentation breaks expectations
 
That will make indenter changes a hell of a lot easier.
 
@Duga Hmmph, wonder what happens when an inspection returns multiple results and one UI...
@Mat'sMug I made an IRefactoringDialog<T> so we can do the tests again.
That's all we need for all the new UI's.
However, Ninject doesn't know how to inject it :/
 
3:17 AM
@Hosch250 nice! can you unify the refactoring UI dependencies with it?
 
Yup.
 
@Comintern and you weren't expecting it the slightest? ;-)
 
For now, though, I'm going to leave the inspection quick fix the way it is.
 
Maybe a little bit. Never saw it go down that hard before though. It was like I flipped the Excel switch off.
 
I think we should new the dialogs up as close as possible to the use case.
 
3:19 AM
BTW if a refactoring requests a reparse before committing rewriter modifications, nothing changes
 
That prevents having to reset the state for multiple quick fixes, for example.
 
Note to self. Don't return null when VBA expects an int.
3
 
I will clean up that presenter stuff, though.
 
@Comintern man you must be seeing error messages that only MS has seen, if anyone did
 
lol
> Error: {placeholder - fill this in if anyone reports it}
 
3:23 AM
LOL
 
I'll know I've finally arrived when they start addressing me by name in error messages...
3
 
does "COM internal error" count?
 
lol
 
oh duh
here I am looking at a bunch of failing tests
...that all do this:
            var refactoring = new IntroduceFieldRefactoring(vbe.Object, state, null);
            refactoring.Refactor(qualifiedSelection);

            Assert.AreEqual(expectedCode, component.CodeModule.Content());
fix:
            var refactoring = new IntroduceFieldRefactoring(vbe.Object, state, null);
            refactoring.Refactor(qualifiedSelection);

            var actual = state.GetRewriter(component).GetText();
            Assert.AreEqual(expectedCode, actual);
 
...and all of a sudden we don't have 1000 tests of the default indenter settings.
 
3:31 AM
            //Input
            const string inputCode =
@"Private Function Foo() As Boolean
Dim bar As Boolean
Foo = True
End Function";
            var selection = new Selection(2, 10, 2, 13);

            //Expectation
            const string expectedCode =
@"Private bar As Boolean
Private Function Foo() As Boolean
Foo = True
End Function";
@Comintern no refactoring currently takes an IIndenter though
but that absolutely can't be ruled out
 
OK, R# - that bug was your fault.
3
 
OH COME ON
Assert.AreEqual failed. Expected:<Private bar As Boolean
Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim _
bat As Date, _
bap As Integer
End Sub>. Actual:<Private bar As Boolean
Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim bat As Date, _
bap As Integer
End Sub>.
I'm very tempted to consider "actual" the correct behavior
"Dim" on its own line, seriously
Assert.AreEqual failed. Expected:<Private bap As Integer
Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim bar As Boolean, _
bat As Date
End Sub>. Actual:<Private bap As Integer
Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim bar As Boolean, _
bat As Date
End Sub>.
^ 2nd failing test
wtf
oh
expected code has 'bat As Date '
there, passes
oh, the other failing test is throwing an NRE
other than that, everything works
lol
test passes a null msgbox
 
If it was passing before, then something is wrong.
The msgbox shouldn't ever be reached, most likely.
 
Apparently we're both passing nulls and msgboxes.
 
@Hosch250 if that's an assumption then a msgbox.Verify call is missing
 
3:40 AM
We only use msgboxes in the refactorings to report errors.
No need to do that if an error isn't expected.
 
but yeah something is wrong
Assert.AreEqual failed. Expected:<Private bat As Date
Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim bar As Boolean, _
_
bap As Integer
End Sub>. Actual:<Private Sub Foo(ByVal buz As Integer, _
ByRef baz As Date)
Dim bar As Boolean, _
bat As Date, _
bap As Integer
End Sub>.
 
Just pass a null, it'll never know the difference if it works right.
 
        if (target == null)
        {
            _messageBox.Show(RubberduckUI.PromoteVariable_InvalidSelection, RubberduckUI.IntroduceParameter_Caption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return;
        }
^ this was the NRE msgbox
by passing a mock msgbox I get to see the test's output, the test fails for the real reason it should be failing
 
[Hosch250/Rubberduck] Hosch250 pushed commit cf20f00b to EncapsulateFieldDialog: Make dialog implement interface
 
i.e. output is not as expected, vs. well the test gave us a null msgbox but don't worry that doesn't happen in production
 
gah
the selection is wrong
that's why the msgbox was popping
it couldn't find the declaration at the old coordinates because I removed the indentation
I'm changing that to use the Declaration overload
 
[retailcoder/Rubberduck] retailcoder pushed commit 99ed1ca5 to rd-next: all IntroduceFieldTests pass
 
TTGTB
 
[rubberduck-vba/Rubberduck] Hosch250 pushed commit 3d4f567c to next: UI is mostly done
[rubberduck-vba/Rubberduck] build for commit 2b9f3d61 on next: AppVeyor build succeeded
[rubberduck-vba/Rubberduck] build for commit b73906e6 on unknown branch: AppVeyor build succeeded
Revert "Remove a couple UI tests"

This reverts commit 1aba356ea670c589ad4be331831cdbfc1e782940.
 

« first day (1014 days earlier)      last day (2166 days later) »