/*
 * Unit test suite for customlinecap
 *
 * Copyright (C) 2008 Nikolay Sivov
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "objbase.h"
#include "gdiplus.h"
#include "wine/test.h"

#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
#define expectf(expected, got) ok(got == expected, "Expected %.2f, got %.2f\n", expected, got)

static void test_constructor_destructor(void)
{
    GpCustomLineCap *custom;
    GpPath *path, *path2;
    GpStatus stat;

    stat = GdipCreatePath(FillModeAlternate, &path);
    expect(Ok, stat);
    stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
    expect(Ok, stat);

    stat = GdipCreatePath(FillModeAlternate, &path2);
    expect(Ok, stat);
    stat = GdipAddPathRectangle(path2, 5.0, 5.0, 10.0, 10.0);
    expect(Ok, stat);

    /* NULL args */
    stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, NULL);
    expect(InvalidParameter, stat);
    stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 0.0, NULL);
    expect(InvalidParameter, stat);
    stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, NULL);
    expect(InvalidParameter, stat);
    stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, &custom);
    expect(InvalidParameter, stat);
    stat = GdipDeleteCustomLineCap(NULL);
    expect(InvalidParameter, stat);

    /* valid args */
    stat = GdipCreateCustomLineCap(NULL, path2, LineCapFlat, 0.0, &custom);
    expect(Ok, stat);
    stat = GdipDeleteCustomLineCap(custom);
    expect(Ok, stat);
    /* it's strange but native returns NotImplemented on stroke == NULL */
    custom = NULL;
    stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 10.0, &custom);
    todo_wine expect(NotImplemented, stat);
    todo_wine ok(custom == NULL, "Expected a failure on creation\n");
    if(stat == Ok) GdipDeleteCustomLineCap(custom);

    GdipDeletePath(path2);
    GdipDeletePath(path);
}

static void test_linejoin(void)
{
    GpCustomLineCap *custom;
    GpPath *path;
    GpLineJoin join;
    GpStatus stat;

    stat = GdipCreatePath(FillModeAlternate, &path);
    expect(Ok, stat);
    stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
    expect(Ok, stat);

    stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
    expect(Ok, stat);

    /* NULL args */
    stat = GdipGetCustomLineCapStrokeJoin(NULL, NULL);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapStrokeJoin(custom, NULL);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapStrokeJoin(NULL, &join);
    expect(InvalidParameter, stat);
    stat = GdipSetCustomLineCapStrokeJoin(NULL, LineJoinBevel);
    expect(InvalidParameter, stat);

    /* LineJoinMiter is default */
    stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
    expect(Ok, stat);
    expect(LineJoinMiter, join);

    /* set/get */
    stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinBevel);
    expect(Ok, stat);
    stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
    expect(Ok, stat);
    expect(LineJoinBevel, join);
    stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinRound);
    expect(Ok, stat);
    stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
    expect(Ok, stat);
    expect(LineJoinRound, join);
    stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinMiterClipped);
    expect(Ok, stat);
    stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
    expect(Ok, stat);
    expect(LineJoinMiterClipped, join);

    GdipDeleteCustomLineCap(custom);
    GdipDeletePath(path);
}

static void test_inset(void)
{
    GpCustomLineCap *custom;
    GpPath *path;
    REAL inset;
    GpStatus stat;

    stat = GdipCreatePath(FillModeAlternate, &path);
    expect(Ok, stat);
    stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
    expect(Ok, stat);

    stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
    expect(Ok, stat);

    /* NULL args */
    stat = GdipGetCustomLineCapBaseInset(NULL, NULL);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapBaseInset(NULL, &inset);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapBaseInset(custom, NULL);
    expect(InvalidParameter, stat);
    /* valid args */
    inset = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapBaseInset(custom, &inset);
    expect(Ok, stat);
    expectf(0.0, inset);

    GdipDeleteCustomLineCap(custom);
    GdipDeletePath(path);
}

static void test_scale(void)
{
    GpCustomLineCap *custom;
    GpPath *path;
    REAL scale;
    GpStatus stat;

    stat = GdipCreatePath(FillModeAlternate, &path);
    expect(Ok, stat);
    stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
    expect(Ok, stat);

    stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
    expect(Ok, stat);

    /* NULL args */
    stat = GdipGetCustomLineCapWidthScale(NULL, NULL);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapWidthScale(NULL, &scale);
    expect(InvalidParameter, stat);
    stat = GdipGetCustomLineCapWidthScale(custom, NULL);
    expect(InvalidParameter, stat);

    stat = GdipSetCustomLineCapWidthScale(NULL, 2.0);
    expect(InvalidParameter, stat);

    /* valid args: read default */
    scale = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapWidthScale(custom, &scale);
    expect(Ok, stat);
    expectf(1.0, scale);

    /* set and read back some scale values: there is no limit for the scale */
    stat = GdipSetCustomLineCapWidthScale(custom, 2.5);
    expect(Ok, stat);
    scale = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapWidthScale(custom, &scale);
    expect(Ok, stat);
    expectf(2.5, scale);

    stat = GdipSetCustomLineCapWidthScale(custom, 42.0);
    expect(Ok, stat);
    scale = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapWidthScale(custom, &scale);
    expect(Ok, stat);
    expectf(42.0, scale);

    stat = GdipSetCustomLineCapWidthScale(custom, 3000.0);
    expect(Ok, stat);
    scale = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapWidthScale(custom, &scale);
    expect(Ok, stat);
    expectf(3000.0, scale);

    stat = GdipSetCustomLineCapWidthScale(custom, 0.0);
    expect(Ok, stat);
    scale = (REAL)0xdeadbeef;
    stat = GdipGetCustomLineCapWidthScale(custom, &scale);
    expect(Ok, stat);
    expectf(0.0, scale);

    GdipDeleteCustomLineCap(custom);
    GdipDeletePath(path);
}

static void test_create_adjustable_cap(void)
{
    GpAdjustableArrowCap *cap;
    REAL inset, scale;
    GpLineJoin join;
    GpStatus stat;
    GpLineCap base;

    stat = GdipCreateAdjustableArrowCap(10.0, 10.0, TRUE, NULL);
todo_wine
    ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);

    stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &cap);
todo_wine
    ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
    if (stat != Ok)
        return;

    stat = GdipGetAdjustableArrowCapMiddleInset(cap, NULL);
    ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);

    stat = GdipGetAdjustableArrowCapMiddleInset(cap, &inset);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);
    ok(inset == 0.0f, "Unexpected middle inset %f\n", inset);

    stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);
    ok(base == LineCapTriangle, "Unexpected base cap %d\n", base);

    stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquare);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);

    stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);
    ok(base == LineCapSquare, "Unexpected base cap %d\n", base);

    stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);

    stat = GdipGetCustomLineCapWidthScale((GpCustomLineCap*)cap, &scale);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);
    ok(scale == 1.0f, "Unexpected width scale %f\n", scale);

    stat = GdipGetCustomLineCapStrokeJoin((GpCustomLineCap*)cap, &join);
    ok(stat == Ok, "Unexpected return code, %d\n", stat);
    ok(join == LineJoinMiter, "Unexpected stroke join %d\n", join);

    GdipDeleteCustomLineCap((GpCustomLineCap*)cap);
}

static void test_captype(void)
{
    GpAdjustableArrowCap *arrowcap;
    GpCustomLineCap *custom;
    CustomLineCapType type;
    GpStatus stat;
    GpPath *path;

    stat = GdipGetCustomLineCapType(NULL, NULL);
    ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);

    type = 10;
    stat = GdipGetCustomLineCapType(NULL, &type);
    ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
    ok(type == 10, "Unexpected cap type, %d\n", type);

    /* default cap */
    stat = GdipCreatePath(FillModeAlternate, &path);
    ok(stat == Ok, "Failed to create path, %d\n", stat);
    stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
    ok(stat == Ok, "AddPathRectangle failed, %d\n", stat);

    stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
    ok(stat == Ok, "Failed to create cap, %d\n", stat);
    stat = GdipGetCustomLineCapType(custom, &type);
    ok(stat == Ok, "Failed to get cap type, %d\n", stat);
    ok(type == CustomLineCapTypeDefault, "Unexpected cap type %d\n", stat);
    GdipDeleteCustomLineCap(custom);
    GdipDeletePath(path);

    /* arrow cap */
    stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &arrowcap);
todo_wine
    ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
    if (stat != Ok)
        return;

    stat = GdipGetCustomLineCapType((GpCustomLineCap*)arrowcap, &type);
    ok(stat == Ok, "Failed to get cap type, %d\n", stat);
    ok(type == CustomLineCapTypeAdjustableArrow, "Unexpected cap type %d\n", stat);

    GdipDeleteCustomLineCap((GpCustomLineCap*)arrowcap);
}

START_TEST(customlinecap)
{
    struct GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;

    gdiplusStartupInput.GdiplusVersion              = 1;
    gdiplusStartupInput.DebugEventCallback          = NULL;
    gdiplusStartupInput.SuppressBackgroundThread    = 0;
    gdiplusStartupInput.SuppressExternalCodecs      = 0;

    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    test_constructor_destructor();
    test_linejoin();
    test_inset();
    test_scale();
    test_create_adjustable_cap();
    test_captype();

    GdiplusShutdown(gdiplusToken);
}
