示例#1
0
def test_broken_schemas():
    # missing required field
    with pytest.raises(
            ManifestValidationError,
            match=("Invalid semantic versioning format")) as exc_info:
        ManifestSchema().load_manifest(
            dict(name="MyPackage", version="broken_version"))
    assert exc_info.value.valid_data == {"name": "MyPackage"}

    # invalid StrictList
    with pytest.raises(
            ManifestValidationError,
            match=("Invalid manifest fields.+keywords")) as exc_info:
        ManifestSchema().load_manifest(
            dict(name="MyPackage", version="1.0.0", keywords=["kw1", "*^[]"]))
    assert list(exc_info.value.messages.keys()) == ["keywords"]
    assert exc_info.value.valid_data["keywords"] == ["kw1"]

    # broken SemVer
    with pytest.raises(ManifestValidationError,
                       match=("Invalid semantic versioning format")):
        ManifestSchema().load_manifest(
            dict(name="MyPackage", version="broken_version"))

    # broken value for Nested
    with pytest.raises(ManifestValidationError,
                       match=r"authors.*Invalid input type"):
        ManifestSchema().load_manifest(
            dict(
                name="MyPackage",
                description="MyDescription",
                keywords=["a", "b"],
                authors=["should be dict here"],
                version="1.2.3",
            ))
def test_package_json_schema():
    contents = """
{
    "name": "tool-scons",
    "description": "SCons software construction tool",
    "keywords": "SCons, build",
    "homepage": "http://www.scons.org",
    "system": ["linux_armv6l", "linux_armv7l", "linux_armv8l"],
    "version": "3.30101.0"
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.PACKAGE_JSON).as_dict()

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "name": "tool-scons",
            "description": "SCons software construction tool",
            "keywords": ["scons", "build"],
            "homepage": "http://www.scons.org",
            "system": ["linux_armv6l", "linux_armv7l", "linux_armv8l"],
            "version": "3.30101.0",
        },
    )

    mp = parser.ManifestParserFactory.new('{"system": "*"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert "system" not in mp.as_dict()

    mp = parser.ManifestParserFactory.new('{"system": "all"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert "system" not in mp.as_dict()

    mp = parser.ManifestParserFactory.new('{"system": "darwin_x86_64"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert mp.as_dict()["system"] == ["darwin_x86_64"]

    # shortcut repository syntax (npm-style)
    contents = """
{
    "name": "tool-github",
    "version": "1.2.0",
    "repository": "github:user/repo"
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.PACKAGE_JSON).as_dict()
    data = ManifestSchema().load_manifest(raw_data)
    assert data["repository"]["url"] == "https://github.com/user/repo.git"
示例#3
0
def test_package_json_schema():
    contents = """
{
    "name": "tool-scons",
    "description": "SCons software construction tool",
    "url": "http://www.scons.org",
    "version": "3.30101.0"
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.PACKAGE_JSON).as_dict()

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "name": "tool-scons",
            "description": "SCons software construction tool",
            "homepage": "http://www.scons.org",
            "version": "3.30101.0",
        },
    )

    mp = parser.ManifestParserFactory.new('{"system": "*"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert "system" not in mp.as_dict()

    mp = parser.ManifestParserFactory.new('{"system": "all"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert "system" not in mp.as_dict()

    mp = parser.ManifestParserFactory.new('{"system": "darwin_x86_64"}',
                                          parser.ManifestFileType.PACKAGE_JSON)
    assert mp.as_dict()["system"] == ["darwin_x86_64"]
示例#4
0
    def find_source_root(self, src):
        if self.manifest_uri:
            mp = (ManifestParserFactory.new_from_file(self.manifest_uri[5:])
                  if self.manifest_uri.startswith("file:") else
                  ManifestParserFactory.new_from_url(self.manifest_uri))
            manifest = ManifestSchema().load_manifest(mp.as_dict())
            include = manifest.get("export", {}).get("include", [])
            if len(include) == 1:
                if not os.path.isdir(os.path.join(src, include[0])):
                    raise PackageException(
                        "Non existing `include` directory `%s` in a package" %
                        include[0])
                return os.path.join(src, include[0])

        for root, _, __ in os.walk(src):
            if ManifestFileType.from_dir(root):
                return root

        return src
示例#5
0
def lib_register(config_url):
    if not config_url.startswith("http://") and not config_url.startswith("https://"):
        raise exception.InvalidLibConfURL(config_url)

    # Validate manifest
    ManifestSchema().load_manifest(
        ManifestParserFactory.new_from_url(config_url).as_dict()
    )

    result = util.get_api_result("/lib/register", data=dict(config_url=config_url))
    if "message" in result and result["message"]:
        click.secho(
            result["message"],
            fg="green" if "successed" in result and result["successed"] else "red",
        )
示例#6
0
def test_broken_schemas():
    # non-strict mode
    data, errors = ManifestSchema(strict=False).load(dict(name="MyPackage"))
    assert set(errors.keys()) == set(["version"])
    assert data.get("version") is None

    # invalid keywords
    data, errors = ManifestSchema(strict=False).load(dict(keywords=["kw1", "*^[]"]))
    assert errors
    assert data["keywords"] == ["kw1"]

    # strict mode

    with pytest.raises(
        ManifestValidationError, match="Missing data for required field"
    ):
        ManifestSchema(strict=True).load(dict(name="MyPackage"))

    # broken SemVer
    with pytest.raises(
        ManifestValidationError, match=("Invalid semantic versioning format")
    ):
        ManifestSchema(strict=True).load(
            dict(name="MyPackage", version="broken_version")
        )

    # broken value for Nested
    with pytest.raises(ManifestValidationError, match=r"authors.*Invalid input type"):
        ManifestSchema(strict=True).load(
            dict(
                name="MyPackage",
                description="MyDescription",
                keywords=["a", "b"],
                authors=["should be dict here"],
                version="1.2.3",
            )
        )
示例#7
0
def test_examples_from_dir(tmpdir_factory):
    package_dir = tmpdir_factory.mktemp("project")
    package_dir.join("library.json").write(
        '{"name": "pkg", "version": "1.0.0", "examples": ["examples/*/*.pde"]}'
    )
    examples_dir = package_dir.mkdir("examples")

    # PlatformIO project #1
    pio_dir = examples_dir.mkdir("PlatformIO").mkdir("hello")
    pio_dir.join(".vimrc").write("")
    pio_ini = pio_dir.join("platformio.ini")
    pio_ini.write("")
    if not WINDOWS:
        pio_dir.join("platformio.ini.copy").mksymlinkto(pio_ini)
    pio_dir.mkdir("include").join("main.h").write("")
    pio_dir.mkdir("src").join("main.cpp").write("")

    # wiring examples
    arduino_dir = examples_dir.mkdir("1. General")
    arduino_dir.mkdir("SomeSketchIno").join("SomeSketchIno.ino").write("")
    arduino_dir.mkdir("SomeSketchPde").join("SomeSketchPde.pde").write("")

    # custom examples
    demo_dir = examples_dir.mkdir("demo")
    demo_dir.join("demo.cpp").write("")
    demo_dir.join("demo.h").write("")
    demo_dir.join("util.h").write("")

    # PlatformIO project #2
    pio_dir = examples_dir.mkdir("world")
    pio_dir.join("platformio.ini").write("")
    pio_dir.join("README").write("")
    pio_dir.join("extra.py").write("")
    pio_dir.mkdir("include").join("world.h").write("")
    pio_dir.mkdir("src").join("world.c").write("")

    # example files in root
    examples_dir.join("root.c").write("")
    examples_dir.join("root.h").write("")

    # invalid example
    examples_dir.mkdir("invalid-example").join("hello.json")

    # Do testing

    raw_data = parser.ManifestParserFactory.new_from_dir(
        str(package_dir)).as_dict()
    assert isinstance(raw_data["examples"], list)
    assert len(raw_data["examples"]) == 6

    def _to_unix_path(path):
        return re.sub(r"[\\/]+", "/", path)

    def _sort_examples(items):
        for i, item in enumerate(items):
            items[i]["base"] = _to_unix_path(items[i]["base"])
            items[i]["files"] = [
                _to_unix_path(f) for f in sorted(items[i]["files"])
            ]
        return sorted(items, key=lambda item: item["name"])

    raw_data["examples"] = _sort_examples(raw_data["examples"])

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "version":
            "1.0.0",
            "name":
            "pkg",
            "examples":
            _sort_examples([
                {
                    "name":
                    "PlatformIO/hello",
                    "base":
                    os.path.join("examples", "PlatformIO", "hello"),
                    "files": [
                        "platformio.ini",
                        os.path.join("include", "main.h"),
                        os.path.join("src", "main.cpp"),
                    ],
                },
                {
                    "name": "1_General/SomeSketchIno",
                    "base": os.path.join("examples", "1. General",
                                         "SomeSketchIno"),
                    "files": ["SomeSketchIno.ino"],
                },
                {
                    "name": "1_General/SomeSketchPde",
                    "base": os.path.join("examples", "1. General",
                                         "SomeSketchPde"),
                    "files": ["SomeSketchPde.pde"],
                },
                {
                    "name": "demo",
                    "base": os.path.join("examples", "demo"),
                    "files": ["demo.h", "util.h", "demo.cpp"],
                },
                {
                    "name":
                    "world",
                    "base":
                    "examples/world",
                    "files": [
                        "platformio.ini",
                        os.path.join("include", "world.h"),
                        os.path.join("src", "world.c"),
                        "README",
                        "extra.py",
                    ],
                },
                {
                    "name": "Examples",
                    "base": "examples",
                    "files": ["root.c", "root.h"],
                },
            ]),
        },
    )
示例#8
0
def test_platform_json_schema():
    contents = """
{
  "name": "atmelavr",
  "title": "Atmel AVR",
  "description": "Atmel AVR 8- and 32-bit MCUs deliver a unique combination of performance, power efficiency and design flexibility. Optimized to speed time to market-and easily adapt to new ones-they are based on the industrys most code-efficient architecture for C and assembly programming.",
  "url": "http://www.atmel.com/products/microcontrollers/avr/default.aspx",
  "homepage": "http://platformio.org/platforms/atmelavr",
  "license": "Apache-2.0",
  "engines": {
    "platformio": "<5"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/platformio/platform-atmelavr.git"
  },
  "version": "1.15.0",
  "frameworks": {
    "arduino": {
      "package": "framework-arduinoavr",
      "script": "builder/frameworks/arduino.py"
    },
    "simba": {
      "package": "framework-simba",
      "script": "builder/frameworks/simba.py"
    }
  },
  "packages": {
    "toolchain-atmelavr": {
      "type": "toolchain",
      "version": "~1.50400.0"
    },
    "framework-arduinoavr": {
      "type": "framework",
      "optional": true,
      "version": "~4.2.0"
    },
    "tool-avrdude": {
      "type": "uploader",
      "optional": true,
      "version": "~1.60300.0"
    }
  }
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.PLATFORM_JSON).as_dict()
    raw_data["frameworks"] = sorted(raw_data["frameworks"])
    raw_data["dependencies"] = sorted(raw_data["dependencies"],
                                      key=lambda a: a["name"])

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "name":
            "atmelavr",
            "title":
            "Atmel AVR",
            "description":
            ("Atmel AVR 8- and 32-bit MCUs deliver a unique combination of "
             "performance, power efficiency and design flexibility. Optimized to "
             "speed time to market-and easily adapt to new ones-they are based "
             "on the industrys most code-efficient architecture for C and "
             "assembly programming."),
            "homepage":
            "http://platformio.org/platforms/atmelavr",
            "license":
            "Apache-2.0",
            "repository": {
                "url": "https://github.com/platformio/platform-atmelavr.git",
                "type": "git",
            },
            "frameworks":
            sorted(["arduino", "simba"]),
            "version":
            "1.15.0",
            "dependencies": [
                {
                    "name": "framework-arduinoavr",
                    "version": "~4.2.0"
                },
                {
                    "name": "tool-avrdude",
                    "version": "~1.60300.0"
                },
                {
                    "name": "toolchain-atmelavr",
                    "version": "~1.50400.0"
                },
            ],
        },
    )
示例#9
0
def test_library_properties_schema():
    contents = """
name=U8glib
version=1.19.1
author=oliver <*****@*****.**>
maintainer=oliver <*****@*****.**>
sentence=A library for monochrome TFTs and OLEDs
paragraph=Supported display controller: SSD1306, SSD1309, SSD1322, SSD1325
category=Display
url=https://github.com/olikraus/u8glib
architectures=avr,sam
depends=First Library (=2.0.0), Second Library (>=1.2.0), Third
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.LIBRARY_PROPERTIES).as_dict()
    raw_data["dependencies"] = sorted(raw_data["dependencies"],
                                      key=lambda a: a["name"])

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "description":
            ("A library for monochrome TFTs and OLEDs. Supported display "
             "controller: SSD1306, SSD1309, SSD1322, SSD1325"),
            "repository": {
                "url": "https://github.com/olikraus/u8glib.git",
                "type": "git",
            },
            "frameworks": ["arduino"],
            "platforms": ["atmelavr", "atmelsam"],
            "version":
            "1.19.1",
            "export": {
                "exclude":
                ["extras", "docs", "tests", "test", "*.doxyfile", "*.pdf"]
            },
            "authors": [{
                "maintainer": True,
                "email": "*****@*****.**",
                "name": "oliver"
            }],
            "keywords": ["display"],
            "name":
            "U8glib",
            "dependencies": [
                {
                    "name": "First Library",
                    "version": "=2.0.0",
                    "frameworks": ["arduino"],
                },
                {
                    "name": "Second Library",
                    "version": ">=1.2.0",
                    "frameworks": ["arduino"],
                },
                {
                    "name": "Third",
                    "frameworks": ["arduino"]
                },
            ],
        },
    )

    # Broken fields
    contents = """
name=Mozzi
version=1.0.3
author=Tim Barrass and contributors as documented in source, and at https://github.com/sensorium/Mozzi/graphs/contributors
maintainer=Tim Barrass <*****@*****.**>
sentence=Sound synthesis library for Arduino
paragraph=With Mozzi, you can construct sounds using familiar synthesis units like oscillators, delays, filters and envelopes.
category=Signal Input/Output
url=https://sensorium.github.io/Mozzi/
architectures=*
dot_a_linkage=false
includes=MozziGuts.h
"""
    raw_data = parser.ManifestParserFactory.new(
        contents,
        parser.ManifestFileType.LIBRARY_PROPERTIES,
        remote_url=("https://raw.githubusercontent.com/sensorium/Mozzi/"
                    "master/library.properties"),
    ).as_dict()

    try:
        ManifestSchema().load_manifest(raw_data)
    except ManifestValidationError as e:
        data = e.valid_data
        errors = e.messages

    assert errors["authors"]

    assert not jsondiff.diff(
        data,
        {
            "name":
            "Mozzi",
            "version":
            "1.0.3",
            "description":
            ("Sound synthesis library for Arduino. With Mozzi, you can construct "
             "sounds using familiar synthesis units like oscillators, delays, "
             "filters and envelopes."),
            "repository": {
                "url": "https://github.com/sensorium/Mozzi.git",
                "type": "git",
            },
            "platforms": ["*"],
            "frameworks": ["arduino"],
            "export": {
                "exclude":
                ["extras", "docs", "tests", "test", "*.doxyfile", "*.pdf"]
            },
            "authors": [{
                "maintainer": True,
                "email": "*****@*****.**",
                "name": "Tim Barrass",
            }],
            "keywords": ["signal", "input", "output"],
            "homepage":
            "https://sensorium.github.io/Mozzi/",
        },
    )
示例#10
0
def test_library_json_schema():
    contents = """
{
  "name": "ArduinoJson",
  "keywords": "JSON, rest, http, web",
  "description": "An elegant and efficient JSON library for embedded systems",
  "homepage": "https://arduinojson.org",
  "repository": {
    "type": "git",
    "url": "https://github.com/bblanchon/ArduinoJson.git"
  },
  "version": "6.12.0",
  "authors": {
    "name": "Benoit Blanchon",
    "url": "https://blog.benoitblanchon.fr"
  },
  "downloadUrl": "https://example.com/package.tar.gz",
  "exclude": [
    "fuzzing",
    "scripts",
    "test",
    "third-party"
  ],
  "frameworks": "arduino",
  "platforms": "*",
  "license": "MIT",
  "examples": [
    {
        "name": "JsonConfigFile",
        "base": "examples/JsonConfigFile",
        "files": ["JsonConfigFile.ino"]
    },
    {
        "name": "JsonHttpClient",
        "base": "examples/JsonHttpClient",
        "files": ["JsonHttpClient.ino"]
    }
  ],
  "dependencies": [
    {"name": "deps1", "version": "1.0.0"},
    {"name": "@owner/deps2", "version": "1.0.0", "frameworks": "arduino"},
    {"name": "deps3", "version": "1.0.0", "platforms": ["ststm32", "sifive"]}
  ]
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.LIBRARY_JSON).as_dict()
    raw_data["dependencies"] = sorted(raw_data["dependencies"],
                                      key=lambda a: a["name"])

    data = ManifestSchema().load_manifest(raw_data)

    assert data["repository"][
        "url"] == "https://github.com/bblanchon/ArduinoJson.git"
    assert data["examples"][1]["base"] == "examples/JsonHttpClient"
    assert data["examples"][1]["files"] == ["JsonHttpClient.ino"]

    assert not jsondiff.diff(
        data,
        {
            "name":
            "ArduinoJson",
            "keywords": ["json", "rest", "http", "web"],
            "description":
            "An elegant and efficient JSON library for embedded systems",
            "homepage":
            "https://arduinojson.org",
            "repository": {
                "url": "https://github.com/bblanchon/ArduinoJson.git",
                "type": "git",
            },
            "version":
            "6.12.0",
            "authors": [{
                "name": "Benoit Blanchon",
                "url": "https://blog.benoitblanchon.fr"
            }],
            "downloadUrl":
            "https://example.com/package.tar.gz",
            "export": {
                "exclude": ["fuzzing", "scripts", "test", "third-party"]
            },
            "frameworks": ["arduino"],
            "platforms": ["*"],
            "license":
            "MIT",
            "examples": [
                {
                    "name": "JsonConfigFile",
                    "base": "examples/JsonConfigFile",
                    "files": ["JsonConfigFile.ino"],
                },
                {
                    "name": "JsonHttpClient",
                    "base": "examples/JsonHttpClient",
                    "files": ["JsonHttpClient.ino"],
                },
            ],
            "dependencies": [
                {
                    "name": "@owner/deps2",
                    "version": "1.0.0",
                    "frameworks": ["arduino"]
                },
                {
                    "name": "deps1",
                    "version": "1.0.0"
                },
                {
                    "name": "deps3",
                    "version": "1.0.0",
                    "platforms": ["ststm32", "sifive"],
                },
            ],
        },
    )

    # legacy dependencies format
    contents = """
{
    "name": "DallasTemperature",
    "version": "3.8.0",
    "dependencies":
    {
        "name": "OneWire",
        "authors": "Paul Stoffregen",
        "frameworks": "arduino"
    }
}
"""
    raw_data = parser.LibraryJsonManifestParser(contents).as_dict()
    data = ManifestSchema().load_manifest(raw_data)
    assert not jsondiff.diff(
        data,
        {
            "name":
            "DallasTemperature",
            "version":
            "3.8.0",
            "dependencies": [{
                "name": "OneWire",
                "authors": ["Paul Stoffregen"],
                "frameworks": ["arduino"],
            }],
        },
    )
示例#11
0
def test_library_json_schema():
    contents = """
{
  "name": "ArduinoJson",
  "keywords": "JSON, rest, http, web",
  "description": "An elegant and efficient JSON library for embedded systems",
  "homepage": "https://arduinojson.org",
  "repository": {
    "type": "git",
    "url": "https://github.com/bblanchon/ArduinoJson.git"
  },
  "version": "6.12.0",
  "authors": {
    "name": "Benoit Blanchon",
    "url": "https://blog.benoitblanchon.fr"
  },
  "exclude": [
    "fuzzing",
    "scripts",
    "test",
    "third-party"
  ],
  "frameworks": "arduino",
  "platforms": "*",
  "license": "MIT",
  "examples": [
    {
        "name": "JsonConfigFile",
        "base": "examples/JsonConfigFile",
        "files": ["JsonConfigFile.ino"]
    },
    {
        "name": "JsonHttpClient",
        "base": "examples/JsonHttpClient",
        "files": ["JsonHttpClient.ino"]
    }
  ]
}
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.LIBRARY_JSON
    ).as_dict()

    data, errors = ManifestSchema(strict=True).load(raw_data)
    assert not errors

    assert data["repository"]["url"] == "https://github.com/bblanchon/ArduinoJson.git"
    assert data["examples"][1]["base"] == "examples/JsonHttpClient"
    assert data["examples"][1]["files"] == ["JsonHttpClient.ino"]

    assert not jsondiff.diff(
        data,
        {
            "name": "ArduinoJson",
            "keywords": ["json", "rest", "http", "web"],
            "description": "An elegant and efficient JSON library for embedded systems",
            "homepage": "https://arduinojson.org",
            "repository": {
                "url": "https://github.com/bblanchon/ArduinoJson.git",
                "type": "git",
            },
            "version": "6.12.0",
            "authors": [
                {"name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr"}
            ],
            "export": {"exclude": ["fuzzing", "scripts", "test", "third-party"]},
            "frameworks": ["arduino"],
            "platforms": ["*"],
            "license": "MIT",
            "examples": [
                {
                    "name": "JsonConfigFile",
                    "base": "examples/JsonConfigFile",
                    "files": ["JsonConfigFile.ino"],
                },
                {
                    "name": "JsonHttpClient",
                    "base": "examples/JsonHttpClient",
                    "files": ["JsonHttpClient.ino"],
                },
            ],
        },
    )
示例#12
0
 def load_manifest(src):
     mp = ManifestParserFactory.new_from_dir(src)
     return ManifestSchema().load_manifest(mp.as_dict())
示例#13
0
# Copyright (c) 2014-present PlatformIO <*****@*****.**>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from platformio.package.manifest.parser import ManifestParserFactory
from platformio.package.manifest.schema import ManifestSchema

mp = ManifestParserFactory.new_from_file('library.json')
parsed = ManifestSchema().load_manifest(mp.as_dict())
示例#14
0
def test_library_properties_schema():
    contents = """
name=U8glib
version=1.19.1
author=oliver <*****@*****.**>
maintainer=oliver <*****@*****.**>
sentence=A library for monochrome TFTs and OLEDs
paragraph=Supported display controller: SSD1306, SSD1309, SSD1322, SSD1325
category=Display
url=https://github.com/olikraus/u8glib
architectures=avr,sam
depends=First Library (=2.0.0), Second Library (>=1.2.0), Third
"""
    raw_data = parser.ManifestParserFactory.new(
        contents, parser.ManifestFileType.LIBRARY_PROPERTIES).as_dict()
    raw_data["dependencies"] = sorted(raw_data["dependencies"],
                                      key=lambda a: a["name"])

    data = ManifestSchema().load_manifest(raw_data)

    assert not jsondiff.diff(
        data,
        {
            "description":
            ("A library for monochrome TFTs and OLEDs. Supported display "
             "controller: SSD1306, SSD1309, SSD1322, SSD1325"),
            "repository": {
                "url": "https://github.com/olikraus/u8glib.git",
                "type": "git",
            },
            "frameworks": ["arduino"],
            "platforms": ["atmelavr", "atmelsam"],
            "version":
            "1.19.1",
            "export": {
                "exclude":
                ["extras", "docs", "tests", "test", "*.doxyfile", "*.pdf"]
            },
            "authors": [{
                "maintainer": True,
                "email": "*****@*****.**",
                "name": "oliver"
            }],
            "keywords": ["display"],
            "name":
            "U8glib",
            "dependencies": [
                {
                    "name": "First Library",
                    "version": "=2.0.0",
                    "frameworks": ["arduino"],
                },
                {
                    "name": "Second Library",
                    "version": ">=1.2.0",
                    "frameworks": ["arduino"],
                },
                {
                    "name": "Third",
                    "frameworks": ["arduino"]
                },
            ],
        },
    )

    # Broken fields
    contents = """
name=Mozzi
version=1.0.3
author=Lorem Ipsum is simply dummy text of the printing and typesetting industry Lorem Ipsum has been the industry's standard dummy text ever since the 1500s  when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries  but also the leap into electronic typesetting  remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages  and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
maintainer=Tim Barrass <*****@*****.**>
sentence=Sound synthesis library for Arduino
paragraph=With Mozzi, you can construct sounds using familiar synthesis units like oscillators, delays, filters and envelopes.
category=Signal Input/Output
url=https://sensorium.github.io/Mozzi/
architectures=*
dot_a_linkage=false
includes=MozziGuts.h
"""
    raw_data = parser.ManifestParserFactory.new(
        contents,
        parser.ManifestFileType.LIBRARY_PROPERTIES,
        remote_url=("https://raw.githubusercontent.com/sensorium/Mozzi/"
                    "master/library.properties"),
    ).as_dict()

    errors = None
    try:
        ManifestSchema().load_manifest(raw_data)
    except ManifestValidationError as e:
        data = e.valid_data
        errors = e.messages

    assert errors["authors"]

    assert not jsondiff.diff(
        data,
        {
            "name":
            "Mozzi",
            "version":
            "1.0.3",
            "description":
            ("Sound synthesis library for Arduino. With Mozzi, you can construct "
             "sounds using familiar synthesis units like oscillators, delays, "
             "filters and envelopes."),
            "repository": {
                "url": "https://github.com/sensorium/Mozzi.git",
                "type": "git",
            },
            "platforms": ["*"],
            "frameworks": ["arduino"],
            "export": {
                "exclude":
                ["extras", "docs", "tests", "test", "*.doxyfile", "*.pdf"]
            },
            "authors": [{
                "maintainer": True,
                "email": "*****@*****.**",
                "name": "Tim Barrass",
            }],
            "keywords": ["signal", "input", "output"],
            "homepage":
            "https://sensorium.github.io/Mozzi/",
        },
    )