Add compilation tests

Added a set of test inputs and expected outputs, for regression testing.
This commit is contained in:
James Westman 2021-10-31 23:29:07 -05:00
parent 53ad4ec69d
commit 5f0eef5f2e
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
21 changed files with 241 additions and 9 deletions

View file

@ -21,7 +21,7 @@ import typing as T
from .ast_utils import *
from .errors import assert_true, AlreadyCaughtError, CompileError, CompilerBugError, MultipleErrors
from .gir import GirContext, get_namespace
from . import gir
from .lsp_utils import Completion, CompletionItemKind
from .tokenizer import Token
from .utils import lazy_prop
@ -33,21 +33,21 @@ class UI(AstNode):
@property
def gir(self):
gir = GirContext()
gir_ctx = gir.GirContext()
self._gir_errors = []
try:
gir.add_namespace(self.children[GtkDirective][0].gir_namespace)
gir_ctx.add_namespace(self.children[GtkDirective][0].gir_namespace)
except CompileError as e:
self._gir_errors.append(e)
for i in self.children[Import]:
try:
gir.add_namespace(i.gir_namespace)
gir_ctx.add_namespace(i.gir_namespace)
except CompileError as e:
self._gir_errors.append(e)
return gir
return gir_ctx
@validate()
@ -86,7 +86,7 @@ class GtkDirective(AstNode):
@property
def gir_namespace(self):
return get_namespace("Gtk", self.tokens["version"])
return gir.get_namespace("Gtk", self.tokens["version"])
def emit_xml(self, xml: XmlEmitter):
@ -95,8 +95,18 @@ class GtkDirective(AstNode):
class Import(AstNode):
@validate("namespace", "version")
def namespace_exists(self):
gir.get_namespace(self.tokens["namespace"], self.tokens["version"])
@property
def gir_namespace(self):
return get_namespace(self.tokens["namespace"], self.tokens["version"])
try:
return gir.get_namespace(self.tokens["namespace"], self.tokens["version"])
except CompileError:
return None
def emit_xml(self, xml):
pass
class Template(AstNode):

View file

@ -30,7 +30,7 @@ class Menu(AstNode):
def emit_xml(self, xml: XmlEmitter):
xml.start_tag(self.tokens["tag"], id=self.tokens["id"])
for child in self.children:
child.emit_xml()
child.emit_xml(xml)
xml.end_tag()
@ -96,7 +96,7 @@ menu_item_shorthand = Group(
)),
Optional(Group(
MenuAttribute,
Sequence(UseLiteral("name", "verb-icon-name"), value),
Sequence(UseLiteral("name", "icon"), value),
)),
StmtEnd().expected("`;`"),
)

View file

@ -0,0 +1,7 @@
using Gtk 4.0;
Box {
visible: bind box2.visible sync-create;
}
Box box2 {}

8
tests/samples/binding.ui Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkBox">
<property name="visible" bind-source="box2" bind-property="visible" bind-flags="sync-create"/>
</object>
<object class="GtkBox" id="box2"></object>
</interface>

View file

@ -0,0 +1,7 @@
using Gtk 4.0;
Window {
[titlebar]
HeaderBar {
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkWindow">
<child type="titlebar">
<object class="GtkHeaderBar"></object>
</child>
</object>
</interface>

10
tests/samples/layout.blp Normal file
View file

@ -0,0 +1,10 @@
using Gtk 4.0;
Grid {
Label {
layout {
column: 0;
row: 1;
}
}
}

14
tests/samples/layout.ui Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkGrid">
<child>
<object class="GtkLabel">
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
</object>
</interface>

20
tests/samples/menu.blp Normal file
View file

@ -0,0 +1,20 @@
using Gtk 4.0;
menu {
label: _("menu label");
test-custom-attribute: 3.1415;
submenu {
section {
label: "test section";
}
item {
label: "test item";
}
item "test item shorthand 1";
item "test item shorthand 2" "app.test-action";
item "test item shorthand 3" "app.test-action" "test-symbolic";
}
}

28
tests/samples/menu.ui Normal file
View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<menu>
<attribute name="label" translatable="yes">menu label</attribute>
<attribute name="test-custom-attribute">3.1415</attribute>
<submenu>
<section>
<attribute name="label">test section</attribute>
</section>
<item>
<attribute name="label">test item</attribute>
</item>
<item>
<attribute name="label">test item shorthand 1</attribute>
</item>
<item>
<attribute name="label">test item shorthand 2</attribute>
<attribute name="action">app.test-action</attribute>
</item>
<item>
<attribute name="label">test item shorthand 3</attribute>
<attribute name="action">app.test-action</attribute>
<attribute name="icon">test-symbolic</attribute>
</item>
</submenu>
</menu>
</interface>

View file

@ -0,0 +1,5 @@
using Gtk 4.0;
Box {
orientation: VERTICAL;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkBox">
<property name="orientation">VERTICAL</property>
</object>
</interface>

6
tests/samples/signal.blp Normal file
View file

@ -0,0 +1,6 @@
using Gtk 4.0;
Button {
clicked => on_button_clicked() swapped;
notify::visible => on_button_notify_visible();
}

8
tests/samples/signal.ui Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkButton">
<signal name="clicked" handler="on_button_clicked" swapped="true"/>
<signal name="notify::visible" handler="on_button_notify_visible"/>
</object>
</interface>

5
tests/samples/style.blp Normal file
View file

@ -0,0 +1,5 @@
using Gtk 4.0;
Label {
style "class-1", "class-2";
}

10
tests/samples/style.ui Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkLabel">
<style>
<class name="class-1"/>
<class name="class-2"/>
</style>
</object>
</interface>

View file

@ -0,0 +1,3 @@
using Gtk 4.0;
template TestTemplate : ApplicationWindow {}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="TestTemplate" parent="GtkApplicationWindow"></template>
</interface>

4
tests/samples/using.blp Normal file
View file

@ -0,0 +1,4 @@
using Gtk 4.0;
using GObject 2.0;
GObject.Object {}

5
tests/samples/using.ui Normal file
View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GObject"></object>
</interface>

61
tests/test_samples.py Normal file
View file

@ -0,0 +1,61 @@
# test_samples.py
#
# Copyright 2021 James Westman <james@jwestman.net>
#
# This file 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 3 of the
# License, or (at your option) any later version.
#
# This file 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 program. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: LGPL-3.0-or-later
import difflib # I love Python
from pathlib import Path
import unittest
from gtkblueprinttool import tokenizer, parser
from gtkblueprinttool.errors import PrintableError
from gtkblueprinttool.tokenizer import Token, TokenType, tokenize
class TestSamples(unittest.TestCase):
def assert_sample(self, name):
with open((Path(__file__).parent / f"samples/{name}.blp").resolve()) as f:
blueprint = f.read()
with open((Path(__file__).parent / f"samples/{name}.ui").resolve()) as f:
expected = f.read()
tokens = tokenizer.tokenize(blueprint)
ast, errors = parser.parse(tokens)
if errors:
raise errors
if len(ast.errors):
raise MultipleErrors(ast.errors)
actual = ast.generate()
if actual.strip() != expected.strip():
diff = difflib.unified_diff(expected.splitlines(), actual.splitlines())
print("\n".join(diff))
raise AssertionError()
def test_samples(self):
self.assert_sample("binding")
self.assert_sample("child_type")
self.assert_sample("layout")
self.assert_sample("menu")
self.assert_sample("property")
self.assert_sample("signal")
self.assert_sample("style")
self.assert_sample("template")
self.assert_sample("using")