Home | History | Annotate | Download | only in parser
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/css/parser/SizesCalcParser.h"
      7 
      8 #include "core/css/CSSPrimitiveValue.h"
      9 #include "core/css/MediaValuesCached.h"
     10 #include "core/css/StylePropertySet.h"
     11 #include "core/css/parser/MediaQueryTokenizer.h"
     12 
     13 #include <gtest/gtest.h>
     14 
     15 namespace WebCore {
     16 
     17 struct TestCase {
     18     const char* input;
     19     const unsigned output;
     20     const bool valid;
     21     const bool dontRunInCSSCalc;
     22 };
     23 
     24 static void initLengthArray(CSSLengthArray& lengthArray)
     25 {
     26     lengthArray.resize(CSSPrimitiveValue::LengthUnitTypeCount);
     27     for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; ++i)
     28         lengthArray.at(i) = 0;
     29 }
     30 
     31 static void verifyCSSCalc(String text, double value, bool valid, unsigned fontSize, unsigned viewportWidth, unsigned viewportHeight)
     32 {
     33     CSSLengthArray lengthArray;
     34     initLengthArray(lengthArray);
     35     RefPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();
     36     propertySet->setProperty(CSSPropertyLeft, text);
     37     RefPtrWillBeRawPtr<CSSValue> cssValue = propertySet->getPropertyCSSValue(CSSPropertyLeft);
     38     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssValue.get());
     39     if (primitiveValue)
     40         primitiveValue->accumulateLengthArray(lengthArray);
     41     else
     42         ASSERT_EQ(valid, false);
     43     int length = lengthArray.at(CSSPrimitiveValue::UnitTypePixels);
     44     length += lengthArray.at(CSSPrimitiveValue::UnitTypeFontSize) * fontSize;
     45     length += lengthArray.at(CSSPrimitiveValue::UnitTypeViewportWidth) * viewportWidth / 100.0;
     46     length += lengthArray.at(CSSPrimitiveValue::UnitTypeViewportHeight) * viewportHeight / 100.0;
     47     ASSERT_EQ(value, length);
     48 }
     49 
     50 
     51 TEST(SizesCalcParserTest, Basic)
     52 {
     53     TestCase testCases[] = {
     54         {"calc(500px + 10em)", 660, true, false},
     55         {"calc(500px + 2 * 10em)", 820, true, false},
     56         {"calc(500px + 2*10em)", 820, true, false},
     57         {"calc(500px + 0.5*10em)", 580, true, false},
     58         {"calc(500px + (0.5*10em + 13px))", 593, true, false},
     59         {"calc(100vw + (0.5*10em + 13px))", 593, true, false},
     60         {"calc(100vh + (0.5*10em + 13px))", 736, true, false},
     61         {"calc(100vh + calc(0.5*10em + 13px))", 736, true, true}, // CSSCalculationValue does not parse internal "calc(".
     62         {"calc(100vh + (50%*10em + 13px))", 0, false, false},
     63         {"calc(50em+13px)", 0, false, false},
     64         {"calc(50em-13px)", 0, false, false},
     65         {"calc(500px + 10)", 0, false, false},
     66         {"calc(500 + 10)", 0, false, false},
     67         {"calc(500px + 10s)", 0, false, true}, // This test ASSERTs in CSSCalculationValue.
     68         {"calc(500px + 1cm)", 537, true, false},
     69         {"calc(500px - 10s)", 0, false, true}, // This test ASSERTs in CSSCalculationValue.
     70         {"calc(500px - 1cm)", 462, true, false},
     71         {"calc(50px*10)", 500, true, false},
     72         {"calc(50px*10px)", 0, false, false},
     73         {"calc(50px/10px)", 0, false, false},
     74         {"calc(500px/10)", 50, true, false},
     75         {"calc(500/10)", 0, false, false},
     76         {"calc(500px/0.5)", 1000, true, false},
     77         {"calc(500px/.5)", 1000, true, false},
     78         {"calc(500/0)", 0, false, false},
     79         {"calc(500px/0)", 0, false, false},
     80         {"calc(-500px/10)", 0, true, true}, // CSSCalculationValue does not clamp negative values to 0.
     81         {"calc(((4) * ((10px))))", 40, true, false},
     82         {"calc(50px / 0)", 0, false, false},
     83         {"calc(50px / (10 + 10))", 2, true, false},
     84         {"calc(50px / (10 - 10))", 0, false, false},
     85         {"calc(50px / (10 * 10))", 0, true, false},
     86         {"calc(50px / (10 / 10))", 50, true, false},
     87         {"calc(200px*)", 0, false, false},
     88         {"calc(+ +200px)", 0, false, false},
     89         {"calc()", 0, false, false},
     90         {"calc(100px + + +100px)", 0, false, false},
     91         {"calc(200px 200px)", 0, false, false},
     92         {"calc(100px * * 2)", 0, false, false},
     93         {"calc(100px @ 2)", 0, false, false},
     94         {"calc(1 flim 2)", 0, false, false},
     95         {"calc(100px @ 2)", 0, false, false},
     96         {"calc(1 flim 2)", 0, false, false},
     97         {"calc(1 flim (2))", 0, false, false},
     98         {0, 0, true, false} // Do not remove the terminator line.
     99     };
    100 
    101 
    102     MediaValuesCached::MediaValuesCachedData data;
    103     data.viewportWidth = 500;
    104     data.viewportHeight = 643;
    105     data.deviceWidth = 500;
    106     data.deviceHeight = 643;
    107     data.devicePixelRatio = 2.0;
    108     data.colorBitsPerComponent = 24;
    109     data.monochromeBitsPerComponent = 0;
    110     data.pointer = MediaValues::MousePointer;
    111     data.defaultFontSize = 16;
    112     data.threeDEnabled = true;
    113     data.scanMediaType = false;
    114     data.screenMediaType = true;
    115     data.printMediaType = false;
    116     data.strictMode = true;
    117     RefPtr<MediaValues> mediaValues = MediaValuesCached::create(data);
    118 
    119     for (unsigned i = 0; testCases[i].input; ++i) {
    120         Vector<MediaQueryToken> tokens;
    121         MediaQueryTokenizer::tokenize(testCases[i].input, tokens);
    122         unsigned output;
    123         bool valid = SizesCalcParser::parse(tokens.begin(), tokens.end(), mediaValues, output);
    124         ASSERT_EQ(testCases[i].valid, valid);
    125         if (valid)
    126             ASSERT_EQ(testCases[i].output, output);
    127     }
    128 
    129     for (unsigned i = 0; testCases[i].input; ++i) {
    130         if (testCases[i].dontRunInCSSCalc)
    131             continue;
    132         verifyCSSCalc(testCases[i].input, testCases[i].output, testCases[i].valid, data.defaultFontSize, data.viewportWidth, data.viewportHeight);
    133     }
    134 }
    135 
    136 } // namespace
    137