@amaster.ai/pi-lark 0.1.2-beta.47 → 0.1.2-beta.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/skills/lark-base/SKILL.md +5 -3
- package/skills/lark-base/references/lark-base-filter-condition.md +179 -0
- package/skills/lark-base/references/lark-base-form-questions-create.md +34 -4
- package/skills/lark-base/references/lark-base-form-questions-update.md +73 -20
- package/skills/lark-base/references/lark-base-view-set-filter.md +11 -137
- package/skills/lark-calendar/SKILL.md +12 -6
- package/skills/lark-calendar/references/lark-calendar-create.md +6 -6
- package/skills/lark-calendar/references/lark-calendar-room-find.md +2 -1
- package/skills/lark-calendar/references/lark-calendar-schedule-clear-time.md +1 -0
- package/skills/lark-calendar/references/lark-calendar-suggestion.md +1 -1
- package/skills/lark-calendar/references/lark-calendar-update.md +7 -4
- package/skills/lark-contact/SKILL.md +18 -2
- package/skills/lark-contact/references/lark-contact-search-bot.md +60 -0
- package/skills/lark-drive/SKILL.md +5 -1
- package/skills/lark-drive/references/lark-drive-member-list.md +65 -0
- package/skills/lark-drive/references/lark-drive-permission-get-setting.md +48 -0
- package/skills/lark-drive/references/lark-drive-search.md +6 -1
- package/skills/lark-drive/references/lark-drive-secure-label.md +1 -1
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance-commands.md +38 -8
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance-outputs.md +10 -10
- package/skills/lark-drive/references/lark-drive-workflow-permission-governance.md +22 -20
- package/skills/lark-slides/SKILL.md +16 -26
- package/skills/lark-slides/references/lark-slides-create.md +14 -5
- package/skills/lark-slides/references/slides_xml_schema_definition.xml +491 -31
- package/skills/lark-slides/references/xml-schema-quick-ref.md +39 -0
- package/skills/lark-slides/scripts/xml_text_overlap_lint.py +424 -32
- package/skills/lark-slides/scripts/xml_text_overlap_lint_test.py +840 -58
- package/skills/lark-task/references/lark-task-create.md +9 -0
|
@@ -343,6 +343,26 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
343
343
|
self.assertEqual(result["summary"]["error_count"], 0)
|
|
344
344
|
self.assertNotIn("issues", result)
|
|
345
345
|
|
|
346
|
+
def test_lint_xml_ignores_chart_parsed_values_roundtrip_tag(self) -> None:
|
|
347
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
348
|
+
"""
|
|
349
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
350
|
+
<data>
|
|
351
|
+
<chart topLeftX="80" topLeftY="80" width="300" height="160">
|
|
352
|
+
<chartData>
|
|
353
|
+
<chartField>
|
|
354
|
+
<chartParsedValues>Africa</chartParsedValues>
|
|
355
|
+
</chartField>
|
|
356
|
+
</chartData>
|
|
357
|
+
</chart>
|
|
358
|
+
</data>
|
|
359
|
+
</slide>
|
|
360
|
+
"""
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
364
|
+
self.assertNotIn("issues", result)
|
|
365
|
+
|
|
346
366
|
def test_lint_xml_limits_chart_roundtrip_attrs_to_matching_tags(self) -> None:
|
|
347
367
|
result = xml_text_overlap_lint.lint_xml(
|
|
348
368
|
"""
|
|
@@ -637,9 +657,10 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
637
657
|
</slide>
|
|
638
658
|
"""
|
|
639
659
|
)
|
|
640
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
641
|
-
self.assertEqual(result["summary"]["warning_count"],
|
|
660
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
661
|
+
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
642
662
|
self.assertEqual(result["slides"][0]["issues"][0]["code"], "text_may_overflow_shape")
|
|
663
|
+
self.assertEqual(result["slides"][0]["issues"][0]["level"], "error")
|
|
643
664
|
self.assertEqual(result["slides"][0]["issues"][0]["elements"], ["source"])
|
|
644
665
|
|
|
645
666
|
def test_lint_xml_reports_text_out_of_canvas_and_warns_for_text_height(self) -> None:
|
|
@@ -660,8 +681,8 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
660
681
|
"""
|
|
661
682
|
)
|
|
662
683
|
issue = result["slides"][0]["issues"][0]
|
|
663
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
664
|
-
self.assertEqual(result["summary"]["warning_count"],
|
|
684
|
+
self.assertEqual(result["summary"]["error_count"], 2)
|
|
685
|
+
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
665
686
|
self.assertEqual(issue["code"], "shape_out_of_canvas")
|
|
666
687
|
self.assertEqual(issue["overflow"], {"left": 0, "top": 0, "right": 160, "bottom": 40})
|
|
667
688
|
|
|
@@ -671,7 +692,7 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
671
692
|
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
672
693
|
<data>
|
|
673
694
|
<shape id="overflowing" type="text" topLeftX="80" topLeftY="80" width="360" height="80">
|
|
674
|
-
<content fontSize="20" lineSpacing="multiple:1.5">
|
|
695
|
+
<content fontSize="20" lineSpacing="multiple:1.5" autoFit="no-auto-fit">
|
|
675
696
|
<p>第一段</p><p>第二段</p><p>第三段</p><p>第四段</p>
|
|
676
697
|
</content>
|
|
677
698
|
</shape>
|
|
@@ -685,20 +706,29 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
685
706
|
<p>第一段</p><p>第二段</p><p>第三段</p><p>第四段</p>
|
|
686
707
|
</content>
|
|
687
708
|
</shape>
|
|
709
|
+
<shape id="shape-auto-fit" type="text" topLeftX="480" topLeftY="240" width="360" height="30">
|
|
710
|
+
<content fontSize="20" lineSpacing="multiple:1.5" autoFit="shape-auto-fit">
|
|
711
|
+
<p>第一段</p><p>第二段</p><p>第三段</p>
|
|
712
|
+
</content>
|
|
713
|
+
</shape>
|
|
688
714
|
</data>
|
|
689
715
|
</slide>
|
|
690
716
|
"""
|
|
691
717
|
)
|
|
692
718
|
issues = result["slides"][0]["issues"]
|
|
693
|
-
|
|
694
|
-
self.assertEqual(result["summary"]["
|
|
695
|
-
|
|
696
|
-
self.
|
|
697
|
-
self.
|
|
698
|
-
self.
|
|
699
|
-
self.
|
|
700
|
-
|
|
701
|
-
self.
|
|
719
|
+
overflow_issues = [issue for issue in issues if issue["code"] == "text_may_overflow_shape"]
|
|
720
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
721
|
+
overflow_ids = {issue["elements"][0] for issue in overflow_issues}
|
|
722
|
+
self.assertIn("overflowing", overflow_ids)
|
|
723
|
+
self.assertNotIn("auto-fit", overflow_ids)
|
|
724
|
+
self.assertNotIn("shape-auto-fit", overflow_ids)
|
|
725
|
+
self.assertNotIn("fitting", overflow_ids)
|
|
726
|
+
overflowing_issue = next(issue for issue in overflow_issues if issue["elements"] == ["overflowing"])
|
|
727
|
+
self.assertEqual(overflowing_issue["line_count"], 4)
|
|
728
|
+
self.assertEqual(overflowing_issue["estimated_height"], 110)
|
|
729
|
+
self.assertEqual(overflowing_issue["available_height"], 80)
|
|
730
|
+
self.assertEqual(overflowing_issue["overflow"], 30)
|
|
731
|
+
self.assertIn('wrap="true" autoFit="normal-auto-fit"', overflowing_issue["message"])
|
|
702
732
|
|
|
703
733
|
def test_lint_xml_uses_fixed_line_spacing_for_text_height_warning(self) -> None:
|
|
704
734
|
result = xml_text_overlap_lint.lint_xml(
|
|
@@ -706,7 +736,7 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
706
736
|
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
707
737
|
<data>
|
|
708
738
|
<shape id="fixed-overflow" type="text" topLeftX="80" topLeftY="80" width="360" height="50">
|
|
709
|
-
<content fontSize="20" lineSpacing="fixed:20">
|
|
739
|
+
<content fontSize="20" lineSpacing="fixed:20" autoFit="no-auto-fit">
|
|
710
740
|
<p>第一段</p><p>第二段</p><p>第三段</p>
|
|
711
741
|
</content>
|
|
712
742
|
</shape>
|
|
@@ -716,17 +746,525 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
716
746
|
)
|
|
717
747
|
issue = result["slides"][0]["issues"][0]
|
|
718
748
|
self.assertEqual(result["summary"]["warning_count"], 1)
|
|
749
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
750
|
+
self.assertEqual(issue["level"], "warning")
|
|
719
751
|
self.assertEqual(issue["line_height"], 20)
|
|
720
752
|
self.assertEqual(issue["estimated_height"], 60)
|
|
721
753
|
self.assertEqual(issue["overflow"], 10)
|
|
722
754
|
|
|
755
|
+
def test_lint_xml_ignores_subpixel_text_height_overflow_tolerance(self) -> None:
|
|
756
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
757
|
+
"""
|
|
758
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
759
|
+
<data>
|
|
760
|
+
<shape id="minor-overflow" type="text" topLeftX="80" topLeftY="80" width="360" height="39.8">
|
|
761
|
+
<content fontSize="20" lineSpacing="fixed:20" autoFit="no-auto-fit">
|
|
762
|
+
<p>第一段</p><p>第二段</p>
|
|
763
|
+
</content>
|
|
764
|
+
</shape>
|
|
765
|
+
</data>
|
|
766
|
+
</slide>
|
|
767
|
+
"""
|
|
768
|
+
)
|
|
769
|
+
overflow_issues = [
|
|
770
|
+
issue
|
|
771
|
+
for issue in result["slides"][0]["issues"]
|
|
772
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
773
|
+
]
|
|
774
|
+
self.assertEqual(overflow_issues, [])
|
|
775
|
+
|
|
776
|
+
def test_lint_xml_allows_single_line_width_estimation_jitter(self) -> None:
|
|
777
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
778
|
+
"""
|
|
779
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
780
|
+
<data>
|
|
781
|
+
<shape id="metric" type="text" topLeftX="80" topLeftY="80" width="152" height="54">
|
|
782
|
+
<content fontSize="36" lineSpacing="multiple:1.2" autoFit="no-auto-fit"><p>4.16万亿</p></content>
|
|
783
|
+
</shape>
|
|
784
|
+
</data>
|
|
785
|
+
</slide>
|
|
786
|
+
"""
|
|
787
|
+
)
|
|
788
|
+
overflow_issues = [
|
|
789
|
+
issue
|
|
790
|
+
for issue in result["slides"][0]["issues"]
|
|
791
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
792
|
+
]
|
|
793
|
+
self.assertEqual(overflow_issues, [])
|
|
794
|
+
|
|
795
|
+
def test_lint_xml_allows_short_metric_text_with_separators_as_single_line(self) -> None:
|
|
796
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
797
|
+
"""
|
|
798
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
799
|
+
<data>
|
|
800
|
+
<shape id="metric" type="text" topLeftX="80" topLeftY="80" width="150" height="50">
|
|
801
|
+
<content textType="title" fontSize="36" autoFit="no-auto-fit"><p>4.16万亿</p></content>
|
|
802
|
+
</shape>
|
|
803
|
+
<shape id="table-number" type="text" topLeftX="80" topLeftY="160" width="25" height="20">
|
|
804
|
+
<content fontSize="10" textAlign="center" autoFit="no-auto-fit"><p>1,380</p></content>
|
|
805
|
+
</shape>
|
|
806
|
+
</data>
|
|
807
|
+
</slide>
|
|
808
|
+
"""
|
|
809
|
+
)
|
|
810
|
+
overflow_issues = [
|
|
811
|
+
issue
|
|
812
|
+
for issue in result["slides"][0]["issues"]
|
|
813
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
814
|
+
]
|
|
815
|
+
self.assertEqual(overflow_issues, [])
|
|
816
|
+
|
|
817
|
+
def test_lint_xml_reports_plain_short_metric_when_it_wraps(self) -> None:
|
|
818
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
819
|
+
"""
|
|
820
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
821
|
+
<data>
|
|
822
|
+
<shape id="plain-age" type="text" topLeftX="80" topLeftY="80" width="50" height="80">
|
|
823
|
+
<content textType="title" fontSize="36" bold="true" autoFit="no-auto-fit"><p>82岁</p></content>
|
|
824
|
+
</shape>
|
|
825
|
+
</data>
|
|
826
|
+
</slide>
|
|
827
|
+
"""
|
|
828
|
+
)
|
|
829
|
+
overflow_issues = [
|
|
830
|
+
issue
|
|
831
|
+
for issue in result["slides"][0]["issues"]
|
|
832
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
833
|
+
]
|
|
834
|
+
self.assertEqual(len(overflow_issues), 1)
|
|
835
|
+
self.assertEqual(overflow_issues[0]["elements"], ["plain-age"])
|
|
836
|
+
|
|
837
|
+
def test_lint_xml_allows_centered_short_label_near_fit_as_single_line(self) -> None:
|
|
838
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
839
|
+
"""
|
|
840
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
841
|
+
<data>
|
|
842
|
+
<shape id="centered-label" type="text" topLeftX="80" topLeftY="80" width="200" height="30">
|
|
843
|
+
<content fontSize="14" bold="true" textAlign="center" autoFit="no-auto-fit">
|
|
844
|
+
<p>参数服务器 (Parameter Server)</p>
|
|
845
|
+
</content>
|
|
846
|
+
</shape>
|
|
847
|
+
</data>
|
|
848
|
+
</slide>
|
|
849
|
+
"""
|
|
850
|
+
)
|
|
851
|
+
overflow_issues = [
|
|
852
|
+
issue
|
|
853
|
+
for issue in result["slides"][0]["issues"]
|
|
854
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
855
|
+
]
|
|
856
|
+
self.assertEqual(overflow_issues, [])
|
|
857
|
+
|
|
858
|
+
def test_lint_xml_allows_headline_near_fit_as_single_line(self) -> None:
|
|
859
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
860
|
+
"""
|
|
861
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
862
|
+
<data>
|
|
863
|
+
<shape id="headline" type="text" topLeftX="80" topLeftY="80" width="700" height="50">
|
|
864
|
+
<content textType="headline" fontSize="26" bold="true" lineSpacing="multiple:1.3" autoFit="no-auto-fit">
|
|
865
|
+
<p>全球半导体市场规模持续高速增长,AI驱动新一轮景气周期</p>
|
|
866
|
+
</content>
|
|
867
|
+
</shape>
|
|
868
|
+
</data>
|
|
869
|
+
</slide>
|
|
870
|
+
"""
|
|
871
|
+
)
|
|
872
|
+
overflow_issues = [
|
|
873
|
+
issue
|
|
874
|
+
for issue in result["slides"][0]["issues"]
|
|
875
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
876
|
+
]
|
|
877
|
+
self.assertEqual(overflow_issues, [])
|
|
878
|
+
|
|
879
|
+
def test_lint_xml_allows_dense_body_line_spacing_estimation_slack(self) -> None:
|
|
880
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
881
|
+
"""
|
|
882
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
883
|
+
<data>
|
|
884
|
+
<shape id="dense-body" type="text" topLeftX="80" topLeftY="80" width="360" height="140">
|
|
885
|
+
<content fontSize="13" bold="true" lineSpacing="multiple:1.7" autoFit="no-auto-fit">
|
|
886
|
+
<p>总体目标:</p>
|
|
887
|
+
<p>建立深度神经网络高效训练的统一理论框架,实现训练效率与模型性能的协同优化。</p>
|
|
888
|
+
<p>具体目标:</p>
|
|
889
|
+
<p>提出自适应优化算法,收敛速度提升 2-3 倍</p>
|
|
890
|
+
<p>实现结构化压缩方法,模型体积减少 10 倍以上</p>
|
|
891
|
+
<p>构建分布式训练策略,64 GPU 加速比 > 50x</p>
|
|
892
|
+
</content>
|
|
893
|
+
</shape>
|
|
894
|
+
</data>
|
|
895
|
+
</slide>
|
|
896
|
+
"""
|
|
897
|
+
)
|
|
898
|
+
overflow_issues = [
|
|
899
|
+
issue
|
|
900
|
+
for issue in result["slides"][0]["issues"]
|
|
901
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
902
|
+
]
|
|
903
|
+
self.assertEqual(overflow_issues, [])
|
|
904
|
+
|
|
905
|
+
def test_lint_xml_reports_dense_body_when_adjusted_height_still_overflows(self) -> None:
|
|
906
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
907
|
+
"""
|
|
908
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
909
|
+
<data>
|
|
910
|
+
<shape id="dense-body" type="text" topLeftX="80" topLeftY="80" width="360" height="100">
|
|
911
|
+
<content fontSize="13" bold="true" lineSpacing="multiple:1.7" autoFit="no-auto-fit">
|
|
912
|
+
<p>总体目标:</p>
|
|
913
|
+
<p>建立深度神经网络高效训练的统一理论框架,实现训练效率与模型性能的协同优化。</p>
|
|
914
|
+
<p>具体目标:</p>
|
|
915
|
+
<p>提出自适应优化算法,收敛速度提升 2-3 倍</p>
|
|
916
|
+
<p>实现结构化压缩方法,模型体积减少 10 倍以上</p>
|
|
917
|
+
<p>构建分布式训练策略,64 GPU 加速比 > 50x</p>
|
|
918
|
+
</content>
|
|
919
|
+
</shape>
|
|
920
|
+
</data>
|
|
921
|
+
</slide>
|
|
922
|
+
"""
|
|
923
|
+
)
|
|
924
|
+
overflow_issues = [
|
|
925
|
+
issue
|
|
926
|
+
for issue in result["slides"][0]["issues"]
|
|
927
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
928
|
+
]
|
|
929
|
+
self.assertEqual(len(overflow_issues), 1)
|
|
930
|
+
self.assertEqual(overflow_issues[0]["elements"], ["dense-body"])
|
|
931
|
+
|
|
932
|
+
def test_lint_xml_reports_letter_spaced_caption_near_fit(self) -> None:
|
|
933
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
934
|
+
"""
|
|
935
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
936
|
+
<data>
|
|
937
|
+
<shape id="caption" type="text" topLeftX="80" topLeftY="80" width="120" height="20">
|
|
938
|
+
<content textType="caption" fontSize="11" letterSpacing="1" autoFit="no-auto-fit">
|
|
939
|
+
<p>RISKS & CHALLENGES</p>
|
|
940
|
+
</content>
|
|
941
|
+
</shape>
|
|
942
|
+
</data>
|
|
943
|
+
</slide>
|
|
944
|
+
"""
|
|
945
|
+
)
|
|
946
|
+
overflow_issues = [
|
|
947
|
+
issue
|
|
948
|
+
for issue in result["slides"][0]["issues"]
|
|
949
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
950
|
+
]
|
|
951
|
+
self.assertEqual(len(overflow_issues), 1)
|
|
952
|
+
self.assertEqual(overflow_issues[0]["elements"], ["caption"])
|
|
953
|
+
|
|
954
|
+
def test_lint_xml_reports_micro_caption_when_wrapping_overflows(self) -> None:
|
|
955
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
956
|
+
"""
|
|
957
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
958
|
+
<data>
|
|
959
|
+
<shape id="micro-caption" type="text" topLeftX="80" topLeftY="60" width="200" height="16">
|
|
960
|
+
<content textType="caption" fontSize="3" lineSpacing="multiple:1.3" letterSpacing="160" autoFit="no-auto-fit">
|
|
961
|
+
<p>MARKET INSIGHT · 市场洞察</p>
|
|
962
|
+
</content>
|
|
963
|
+
</shape>
|
|
964
|
+
</data>
|
|
965
|
+
</slide>
|
|
966
|
+
"""
|
|
967
|
+
)
|
|
968
|
+
overflow_issues = [
|
|
969
|
+
issue
|
|
970
|
+
for issue in result["slides"][0]["issues"]
|
|
971
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
972
|
+
]
|
|
973
|
+
self.assertEqual(len(overflow_issues), 1)
|
|
974
|
+
self.assertEqual(overflow_issues[0]["elements"], ["micro-caption"])
|
|
975
|
+
|
|
976
|
+
def test_lint_xml_text_may_overflow_shape_upgrades_to_error_above_threshold(self) -> None:
|
|
977
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
978
|
+
"""
|
|
979
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
980
|
+
<data>
|
|
981
|
+
<shape id="just-warning" type="text" topLeftX="80" topLeftY="80" width="360" height="50">
|
|
982
|
+
<content fontSize="20" lineSpacing="fixed:20" autoFit="no-auto-fit">
|
|
983
|
+
<p>第一段</p><p>第二段</p><p>第三段</p>
|
|
984
|
+
</content>
|
|
985
|
+
</shape>
|
|
986
|
+
<shape id="error-overflow" type="text" topLeftX="80" topLeftY="200" width="360" height="30">
|
|
987
|
+
<content fontSize="20" lineSpacing="fixed:20" autoFit="no-auto-fit">
|
|
988
|
+
<p>第一段</p><p>第二段</p><p>第三段</p>
|
|
989
|
+
</content>
|
|
990
|
+
</shape>
|
|
991
|
+
</data>
|
|
992
|
+
</slide>
|
|
993
|
+
"""
|
|
994
|
+
)
|
|
995
|
+
issues = {issue["elements"][0]: issue for issue in result["slides"][0]["issues"]}
|
|
996
|
+
self.assertEqual(issues["just-warning"]["level"], "warning")
|
|
997
|
+
self.assertEqual(issues["just-warning"]["overflow"], 10)
|
|
998
|
+
self.assertEqual(issues["error-overflow"]["level"], "error")
|
|
999
|
+
self.assertEqual(issues["error-overflow"]["overflow"], 30)
|
|
1000
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1001
|
+
self.assertEqual(result["summary"]["warning_count"], 1)
|
|
1002
|
+
|
|
1003
|
+
def test_lint_xml_text_may_overflow_shape_downgrades_background_decoration_to_info(self) -> None:
|
|
1004
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1005
|
+
"""
|
|
1006
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1007
|
+
<data>
|
|
1008
|
+
<shape id="bg-deco" type="text" topLeftX="0" topLeftY="0" width="600" height="80" alpha="0.3">
|
|
1009
|
+
<content fontSize="120" lineSpacing="fixed:120" autoFit="no-auto-fit"><p>2026</p></content>
|
|
1010
|
+
</shape>
|
|
1011
|
+
<shape id="foreground" type="text" topLeftX="40" topLeftY="20" width="400" height="60">
|
|
1012
|
+
<content fontSize="20" lineSpacing="fixed:24"><p>Annual Report</p></content>
|
|
1013
|
+
</shape>
|
|
1014
|
+
</data>
|
|
1015
|
+
</slide>
|
|
1016
|
+
"""
|
|
1017
|
+
)
|
|
1018
|
+
issues = {
|
|
1019
|
+
issue["elements"][0]: issue
|
|
1020
|
+
for issue in result["slides"][0]["issues"]
|
|
1021
|
+
if issue["code"] == "text_may_overflow_shape"
|
|
1022
|
+
}
|
|
1023
|
+
self.assertEqual(issues["bg-deco"]["level"], "info")
|
|
1024
|
+
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
1025
|
+
self.assertEqual(result["summary"]["info_count"], 1)
|
|
1026
|
+
self.assertEqual(result["slides"][0]["infos"], [issues["bg-deco"]])
|
|
1027
|
+
self.assertIn("background decoration", issues["bg-deco"]["message"])
|
|
1028
|
+
|
|
1029
|
+
def test_lint_xml_reports_shape_alpha_ghost_text_out_of_canvas_but_allows_overlap(self) -> None:
|
|
1030
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1031
|
+
"""
|
|
1032
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1033
|
+
<data>
|
|
1034
|
+
<shape id="ghost-number" type="text" topLeftX="-60" topLeftY="30" width="360" height="180" alpha="0.2">
|
|
1035
|
+
<content fontSize="160" lineSpacing="fixed:160" wrap="false"><p>01</p></content>
|
|
1036
|
+
</shape>
|
|
1037
|
+
<shape id="title" type="text" topLeftX="80" topLeftY="80" width="360" height="80">
|
|
1038
|
+
<content fontSize="30" lineSpacing="fixed:36"><p>Annual Review</p></content>
|
|
1039
|
+
</shape>
|
|
1040
|
+
</data>
|
|
1041
|
+
</slide>
|
|
1042
|
+
"""
|
|
1043
|
+
)
|
|
1044
|
+
codes = [issue["code"] for issue in result["slides"][0]["issues"]]
|
|
1045
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1046
|
+
self.assertIn("shape_out_of_canvas", codes)
|
|
1047
|
+
self.assertNotIn("bbox_overlap", codes)
|
|
1048
|
+
|
|
1049
|
+
def test_lint_xml_reports_content_color_alpha_ghost_text_out_of_canvas_but_allows_overlap(self) -> None:
|
|
1050
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1051
|
+
"""
|
|
1052
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1053
|
+
<data>
|
|
1054
|
+
<shape id="ghost-year" type="text" topLeftX="760" topLeftY="20" width="260" height="160">
|
|
1055
|
+
<content fontSize="140" color="rgba(0,0,0,0.2)" lineSpacing="fixed:140" wrap="false"><p>2026</p></content>
|
|
1056
|
+
</shape>
|
|
1057
|
+
<shape id="headline" type="text" topLeftX="700" topLeftY="70" width="220" height="80">
|
|
1058
|
+
<content fontSize="28" lineSpacing="fixed:34"><p>Forecast</p></content>
|
|
1059
|
+
</shape>
|
|
1060
|
+
</data>
|
|
1061
|
+
</slide>
|
|
1062
|
+
"""
|
|
1063
|
+
)
|
|
1064
|
+
codes = [issue["code"] for issue in result["slides"][0]["issues"]]
|
|
1065
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1066
|
+
self.assertIn("shape_out_of_canvas", codes)
|
|
1067
|
+
self.assertNotIn("bbox_overlap", codes)
|
|
1068
|
+
|
|
1069
|
+
def test_lint_xml_reports_faint_medium_ghost_text_out_of_canvas_but_allows_overlap(self) -> None:
|
|
1070
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1071
|
+
"""
|
|
1072
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1073
|
+
<data>
|
|
1074
|
+
<shape id="medium-ghost" type="text" topLeftX="820" topLeftY="300" width="270" height="72" alpha="0.32">
|
|
1075
|
+
<content fontSize="40" lineSpacing="fixed:40" wrap="false"><p>OFF EDGE</p></content>
|
|
1076
|
+
</shape>
|
|
1077
|
+
<shape id="caption" type="text" topLeftX="760" topLeftY="315" width="180" height="36">
|
|
1078
|
+
<content fontSize="16" lineSpacing="fixed:20"><p>Readable caption</p></content>
|
|
1079
|
+
</shape>
|
|
1080
|
+
</data>
|
|
1081
|
+
</slide>
|
|
1082
|
+
"""
|
|
1083
|
+
)
|
|
1084
|
+
codes = [issue["code"] for issue in result["slides"][0]["issues"]]
|
|
1085
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1086
|
+
self.assertIn("shape_out_of_canvas", codes)
|
|
1087
|
+
self.assertNotIn("bbox_overlap", codes)
|
|
1088
|
+
|
|
1089
|
+
def test_lint_xml_allows_ghost_text_image_overlap(self) -> None:
|
|
1090
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1091
|
+
"""
|
|
1092
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1093
|
+
<data>
|
|
1094
|
+
<shape id="ghost-label" type="text" topLeftX="100" topLeftY="40" width="560" height="160" alpha="0.2">
|
|
1095
|
+
<content fontSize="120" lineSpacing="fixed:120" wrap="false"><p>2026</p></content>
|
|
1096
|
+
</shape>
|
|
1097
|
+
<img id="photo" src="token" topLeftX="160" topLeftY="70" width="260" height="160"/>
|
|
1098
|
+
<shape id="title" type="text" topLeftX="610" topLeftY="95" width="320" height="60">
|
|
1099
|
+
<content fontSize="28" lineSpacing="fixed:34"><p>Annual Review</p></content>
|
|
1100
|
+
</shape>
|
|
1101
|
+
</data>
|
|
1102
|
+
</slide>
|
|
1103
|
+
"""
|
|
1104
|
+
)
|
|
1105
|
+
codes = [issue["code"] for issue in result["slides"][0]["issues"]]
|
|
1106
|
+
self.assertNotIn("image_covers_text", codes)
|
|
1107
|
+
self.assertNotIn("bbox_overlap", codes)
|
|
1108
|
+
|
|
1109
|
+
def test_lint_slide_allows_ghost_text_whiteboard_overlap(self) -> None:
|
|
1110
|
+
result = xml_text_overlap_lint.lint_slide(
|
|
1111
|
+
"""
|
|
1112
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1113
|
+
<data>
|
|
1114
|
+
<whiteboard id="board" topLeftX="180" topLeftY="70" width="420" height="300"/>
|
|
1115
|
+
<shape id="ghost-label" type="text" topLeftX="100" topLeftY="40" width="560" height="160" alpha="0.2">
|
|
1116
|
+
<content fontSize="120" lineSpacing="fixed:120" wrap="false"><p>2026</p></content>
|
|
1117
|
+
</shape>
|
|
1118
|
+
<shape id="title" type="text" topLeftX="610" topLeftY="95" width="220" height="60">
|
|
1119
|
+
<content fontSize="28" lineSpacing="fixed:34"><p>Annual Review</p></content>
|
|
1120
|
+
</shape>
|
|
1121
|
+
</data>
|
|
1122
|
+
</slide>
|
|
1123
|
+
""",
|
|
1124
|
+
1,
|
|
1125
|
+
)
|
|
1126
|
+
codes = [issue["code"] for issue in result["issues"]]
|
|
1127
|
+
self.assertNotIn("whiteboard_external_overlap", codes)
|
|
1128
|
+
|
|
1129
|
+
def test_lint_xml_reports_faint_ghost_text_out_of_canvas_without_area_threshold(self) -> None:
|
|
1130
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1131
|
+
"""
|
|
1132
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1133
|
+
<data>
|
|
1134
|
+
<shape id="small-ghost" type="text" topLeftX="940" topLeftY="300" width="40" height="40" alpha="0.32">
|
|
1135
|
+
<content fontSize="36" lineSpacing="fixed:36" wrap="false"><p>土</p></content>
|
|
1136
|
+
</shape>
|
|
1137
|
+
</data>
|
|
1138
|
+
</slide>
|
|
1139
|
+
"""
|
|
1140
|
+
)
|
|
1141
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1142
|
+
self.assertEqual(result["slides"][0]["issues"][0]["code"], "shape_out_of_canvas")
|
|
1143
|
+
|
|
1144
|
+
def test_lint_xml_keeps_out_of_canvas_error_for_medium_text_without_faint_alpha(self) -> None:
|
|
1145
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1146
|
+
"""
|
|
1147
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1148
|
+
<data>
|
|
1149
|
+
<shape id="medium-not-ghost" type="text" topLeftX="820" topLeftY="300" width="270" height="72" alpha="0.36">
|
|
1150
|
+
<content fontSize="54" lineSpacing="fixed:54" wrap="false"><p>OFF EDGE</p></content>
|
|
1151
|
+
</shape>
|
|
1152
|
+
</data>
|
|
1153
|
+
</slide>
|
|
1154
|
+
"""
|
|
1155
|
+
)
|
|
1156
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1157
|
+
self.assertEqual(result["slides"][0]["issues"][0]["code"], "shape_out_of_canvas")
|
|
1158
|
+
self.assertEqual(result["slides"][0]["issues"][0]["elements"], ["medium-not-ghost"])
|
|
1159
|
+
|
|
1160
|
+
def test_lint_xml_keeps_out_of_canvas_error_for_half_alpha_large_text(self) -> None:
|
|
1161
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1162
|
+
"""
|
|
1163
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1164
|
+
<data>
|
|
1165
|
+
<shape id="half-alpha" type="text" topLeftX="760" topLeftY="20" width="260" height="160">
|
|
1166
|
+
<content fontSize="140" color="rgba(0,0,0,0.5)" lineSpacing="fixed:140" wrap="false"><p>2026</p></content>
|
|
1167
|
+
</shape>
|
|
1168
|
+
</data>
|
|
1169
|
+
</slide>
|
|
1170
|
+
"""
|
|
1171
|
+
)
|
|
1172
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
1173
|
+
self.assertEqual(result["slides"][0]["issues"][0]["code"], "shape_out_of_canvas")
|
|
1174
|
+
self.assertEqual(result["slides"][0]["issues"][0]["elements"], ["half-alpha"])
|
|
1175
|
+
|
|
1176
|
+
def test_lint_xml_text_may_overflow_shape_keeps_error_when_alpha_not_low(self) -> None:
|
|
1177
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1178
|
+
"""
|
|
1179
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1180
|
+
<data>
|
|
1181
|
+
<shape id="opaque-big" type="text" topLeftX="0" topLeftY="0" width="600" height="80" alpha="0.9">
|
|
1182
|
+
<content fontSize="120" lineSpacing="fixed:120" autoFit="no-auto-fit"><p>2026</p></content>
|
|
1183
|
+
</shape>
|
|
1184
|
+
<shape id="foreground" type="text" topLeftX="40" topLeftY="20" width="400" height="60">
|
|
1185
|
+
<content fontSize="20" lineSpacing="fixed:24"><p>Annual Report</p></content>
|
|
1186
|
+
</shape>
|
|
1187
|
+
</data>
|
|
1188
|
+
</slide>
|
|
1189
|
+
"""
|
|
1190
|
+
)
|
|
1191
|
+
issue = next(
|
|
1192
|
+
issue
|
|
1193
|
+
for issue in result["slides"][0]["issues"]
|
|
1194
|
+
if issue["code"] == "text_may_overflow_shape" and issue["elements"] == ["opaque-big"]
|
|
1195
|
+
)
|
|
1196
|
+
self.assertEqual(issue["level"], "error")
|
|
1197
|
+
|
|
1198
|
+
def test_lint_xml_text_may_overflow_shape_keeps_error_when_no_foreground_text(self) -> None:
|
|
1199
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1200
|
+
"""
|
|
1201
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1202
|
+
<data>
|
|
1203
|
+
<shape id="lonely-big" type="text" topLeftX="0" topLeftY="0" width="600" height="80" alpha="0.3">
|
|
1204
|
+
<content fontSize="120" lineSpacing="fixed:120" autoFit="no-auto-fit"><p>2026</p></content>
|
|
1205
|
+
</shape>
|
|
1206
|
+
</data>
|
|
1207
|
+
</slide>
|
|
1208
|
+
"""
|
|
1209
|
+
)
|
|
1210
|
+
issue = next(
|
|
1211
|
+
issue
|
|
1212
|
+
for issue in result["slides"][0]["issues"]
|
|
1213
|
+
if issue["code"] == "text_may_overflow_shape" and issue["elements"] == ["lonely-big"]
|
|
1214
|
+
)
|
|
1215
|
+
self.assertEqual(issue["level"], "error")
|
|
1216
|
+
|
|
1217
|
+
def test_lint_xml_text_may_overflow_shape_keeps_error_when_foreground_alpha_zero(self) -> None:
|
|
1218
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1219
|
+
"""
|
|
1220
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1221
|
+
<data>
|
|
1222
|
+
<shape id="bg-deco" type="text" topLeftX="0" topLeftY="0" width="600" height="80" alpha="0.3">
|
|
1223
|
+
<content fontSize="120" lineSpacing="fixed:120" autoFit="no-auto-fit"><p>2026</p></content>
|
|
1224
|
+
</shape>
|
|
1225
|
+
<shape id="transparent-foreground" type="text" topLeftX="40" topLeftY="20" width="400" height="60" alpha="0">
|
|
1226
|
+
<content fontSize="20" lineSpacing="fixed:24"><p>Annual Report</p></content>
|
|
1227
|
+
</shape>
|
|
1228
|
+
</data>
|
|
1229
|
+
</slide>
|
|
1230
|
+
"""
|
|
1231
|
+
)
|
|
1232
|
+
issue = next(
|
|
1233
|
+
issue
|
|
1234
|
+
for issue in result["slides"][0]["issues"]
|
|
1235
|
+
if issue["code"] == "text_may_overflow_shape" and issue["elements"] == ["bg-deco"]
|
|
1236
|
+
)
|
|
1237
|
+
self.assertEqual(issue["level"], "error")
|
|
1238
|
+
|
|
1239
|
+
def test_lint_xml_text_may_overflow_shape_keeps_error_when_foreground_is_below_in_order(self) -> None:
|
|
1240
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1241
|
+
"""
|
|
1242
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1243
|
+
<data>
|
|
1244
|
+
<shape id="foreground" type="text" topLeftX="40" topLeftY="20" width="400" height="60">
|
|
1245
|
+
<content fontSize="20" lineSpacing="fixed:24"><p>Annual Report</p></content>
|
|
1246
|
+
</shape>
|
|
1247
|
+
<shape id="top-big" type="text" topLeftX="0" topLeftY="0" width="600" height="80" alpha="0.3">
|
|
1248
|
+
<content fontSize="120" lineSpacing="fixed:120" autoFit="no-auto-fit"><p>2026</p></content>
|
|
1249
|
+
</shape>
|
|
1250
|
+
</data>
|
|
1251
|
+
</slide>
|
|
1252
|
+
"""
|
|
1253
|
+
)
|
|
1254
|
+
issue = next(
|
|
1255
|
+
issue
|
|
1256
|
+
for issue in result["slides"][0]["issues"]
|
|
1257
|
+
if issue["code"] == "text_may_overflow_shape" and issue["elements"] == ["top-big"]
|
|
1258
|
+
)
|
|
1259
|
+
self.assertEqual(issue["level"], "error")
|
|
1260
|
+
|
|
723
1261
|
def test_lint_xml_uses_paragraph_spacing_overrides_for_text_height_warning(self) -> None:
|
|
724
1262
|
result = xml_text_overlap_lint.lint_xml(
|
|
725
1263
|
"""
|
|
726
1264
|
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
727
1265
|
<data>
|
|
728
|
-
<shape id="paragraph-overflow" type="text" topLeftX="80" topLeftY="80" width="360" height="
|
|
729
|
-
<content fontSize="20" lineSpacing="multiple:1.5">
|
|
1266
|
+
<shape id="paragraph-overflow" type="text" topLeftX="80" topLeftY="80" width="360" height="30">
|
|
1267
|
+
<content fontSize="20" lineSpacing="multiple:1.5" autoFit="no-auto-fit">
|
|
730
1268
|
<p lineSpacing="fixed:10" beforeLineSpacing="fixed:5" afterLineSpacing="fixed:5">第一行<br/>第二行</p>
|
|
731
1269
|
</content>
|
|
732
1270
|
</shape>
|
|
@@ -745,7 +1283,36 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
745
1283
|
self.assertEqual(issues[0]["line_count"], 2)
|
|
746
1284
|
self.assertEqual(issues[0]["line_height"], 10)
|
|
747
1285
|
self.assertEqual(issues[0]["estimated_height"], 40)
|
|
748
|
-
self.assertEqual(issues[0]["overflow"],
|
|
1286
|
+
self.assertEqual(issues[0]["overflow"], 10)
|
|
1287
|
+
|
|
1288
|
+
def test_lint_xml_uses_letter_spacing_for_text_overflow_warning(self) -> None:
|
|
1289
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1290
|
+
"""
|
|
1291
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1292
|
+
<data>
|
|
1293
|
+
<shape id="baseline" type="text" topLeftX="0" topLeftY="0" width="120" height="30">
|
|
1294
|
+
<content fontSize="20" lineSpacing="multiple:1.5" autoFit="no-auto-fit"><p>一二三四五六</p></content>
|
|
1295
|
+
</shape>
|
|
1296
|
+
<shape id="content-spaced" type="text" topLeftX="200" topLeftY="0" width="120" height="30">
|
|
1297
|
+
<content fontSize="20" lineSpacing="multiple:1.5" letterSpacing="2" autoFit="no-auto-fit"><p>一二三四五六</p></content>
|
|
1298
|
+
</shape>
|
|
1299
|
+
<shape id="paragraph-spaced" type="text" topLeftX="400" topLeftY="0" width="120" height="30">
|
|
1300
|
+
<content fontSize="20" lineSpacing="multiple:1.5" autoFit="no-auto-fit"><p letterSpacing="2">一二三四五六</p></content>
|
|
1301
|
+
</shape>
|
|
1302
|
+
</data>
|
|
1303
|
+
</slide>
|
|
1304
|
+
"""
|
|
1305
|
+
)
|
|
1306
|
+
issues = result["slides"][0]["issues"]
|
|
1307
|
+
overflow_ids = [issue["elements"][0] for issue in issues if issue["code"] == "text_may_overflow_shape"]
|
|
1308
|
+
self.assertNotIn("baseline", overflow_ids)
|
|
1309
|
+
self.assertIn("content-spaced", overflow_ids)
|
|
1310
|
+
self.assertIn("paragraph-spaced", overflow_ids)
|
|
1311
|
+
by_id = {issue["elements"][0]: issue for issue in issues if issue["code"] == "text_may_overflow_shape"}
|
|
1312
|
+
self.assertEqual(by_id["content-spaced"]["line_count"], 2)
|
|
1313
|
+
self.assertEqual(by_id["content-spaced"]["estimated_height"], 50)
|
|
1314
|
+
self.assertEqual(by_id["content-spaced"]["overflow"], 20)
|
|
1315
|
+
self.assertEqual(by_id["paragraph-spaced"]["line_count"], 2)
|
|
749
1316
|
|
|
750
1317
|
def test_strip_xml_paragraphs_preserves_br_as_hard_line_break(self) -> None:
|
|
751
1318
|
self.assertEqual(
|
|
@@ -753,7 +1320,7 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
753
1320
|
"第一行\n第二行\n第三行",
|
|
754
1321
|
)
|
|
755
1322
|
|
|
756
|
-
def
|
|
1323
|
+
def test_lint_xml_allows_template_style_images_outside_canvas(self) -> None:
|
|
757
1324
|
result = xml_text_overlap_lint.lint_xml(
|
|
758
1325
|
"""
|
|
759
1326
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
@@ -771,9 +1338,8 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
771
1338
|
</presentation>
|
|
772
1339
|
"""
|
|
773
1340
|
)
|
|
774
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
1341
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
775
1342
|
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
776
|
-
self.assertEqual(result["slides"][0]["errors"][0]["code"], "img_out_of_canvas")
|
|
777
1343
|
|
|
778
1344
|
def test_extract_elements_preserves_supported_element_geometry_order_and_text_metadata(self) -> None:
|
|
779
1345
|
elements = xml_text_overlap_lint.extract_elements(
|
|
@@ -807,7 +1373,7 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
807
1373
|
self.assertEqual(elements[1]["fontSize"], 28)
|
|
808
1374
|
self.assertEqual(elements[1]["text"], "Growth & scale\nFocused execution")
|
|
809
1375
|
|
|
810
|
-
def
|
|
1376
|
+
def test_lint_xml_ignores_small_out_of_bounds_images(self) -> None:
|
|
811
1377
|
result = xml_text_overlap_lint.lint_xml(
|
|
812
1378
|
"""
|
|
813
1379
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
@@ -819,10 +1385,9 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
819
1385
|
</presentation>
|
|
820
1386
|
"""
|
|
821
1387
|
)
|
|
822
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
823
|
-
self.assertEqual(result["slides"][0]["errors"][0]["code"], "img_out_of_canvas")
|
|
1388
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
824
1389
|
|
|
825
|
-
def
|
|
1390
|
+
def test_lint_xml_ignores_out_of_canvas_images(self) -> None:
|
|
826
1391
|
result = xml_text_overlap_lint.lint_xml(
|
|
827
1392
|
"""
|
|
828
1393
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
@@ -835,13 +1400,9 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
835
1400
|
</presentation>
|
|
836
1401
|
"""
|
|
837
1402
|
)
|
|
838
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
839
|
-
self.assertEqual(
|
|
840
|
-
[issue["code"] for issue in result["slides"][0]["errors"]],
|
|
841
|
-
["img_out_of_canvas", "img_out_of_canvas"],
|
|
842
|
-
)
|
|
1403
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
843
1404
|
|
|
844
|
-
def
|
|
1405
|
+
def test_lint_xml_ignores_full_bleed_images_outside_canvas(self) -> None:
|
|
845
1406
|
result = xml_text_overlap_lint.lint_xml(
|
|
846
1407
|
"""
|
|
847
1408
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
@@ -853,10 +1414,9 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
853
1414
|
</presentation>
|
|
854
1415
|
"""
|
|
855
1416
|
)
|
|
856
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
857
|
-
self.assertEqual(result["slides"][0]["errors"][0]["code"], "img_out_of_canvas")
|
|
1417
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
858
1418
|
|
|
859
|
-
def
|
|
1419
|
+
def test_lint_xml_reports_text_and_chart_but_not_image_out_of_canvas(self) -> None:
|
|
860
1420
|
result = xml_text_overlap_lint.lint_xml(
|
|
861
1421
|
"""
|
|
862
1422
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
@@ -871,17 +1431,16 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
871
1431
|
"""
|
|
872
1432
|
)
|
|
873
1433
|
issues = result["slides"][0]["issues"]
|
|
874
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
1434
|
+
self.assertEqual(result["summary"]["error_count"], 2)
|
|
875
1435
|
self.assertEqual(
|
|
876
1436
|
[(issue["code"], issue["elements"], issue["overflow"]) for issue in issues],
|
|
877
1437
|
[
|
|
878
1438
|
("shape_out_of_canvas", ["outside-shape"], {"left": 10, "top": 0, "right": 0, "bottom": 0}),
|
|
879
|
-
("img_out_of_canvas", ["outside-img"], {"left": 0, "top": 20, "right": 0, "bottom": 0}),
|
|
880
1439
|
("chart_out_of_canvas", ["outside-chart"], {"left": 0, "top": 0, "right": 40, "bottom": 0}),
|
|
881
1440
|
],
|
|
882
1441
|
)
|
|
883
1442
|
|
|
884
|
-
def
|
|
1443
|
+
def test_lint_xml_ignores_line_out_of_canvas(self) -> None:
|
|
885
1444
|
result = xml_text_overlap_lint.lint_xml(
|
|
886
1445
|
"""
|
|
887
1446
|
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
@@ -895,11 +1454,189 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
895
1454
|
"""
|
|
896
1455
|
)
|
|
897
1456
|
|
|
898
|
-
|
|
899
|
-
self.assertEqual(
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1457
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1458
|
+
self.assertEqual(result["slides"][0]["issues"], [])
|
|
1459
|
+
|
|
1460
|
+
def test_lint_xml_reports_horizontal_line_crossing_headline_glyphs(self) -> None:
|
|
1461
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1462
|
+
"""
|
|
1463
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1464
|
+
<data>
|
|
1465
|
+
<shape id="title" type="text" topLeftX="80" topLeftY="200" width="500" height="90">
|
|
1466
|
+
<content fontSize="60"><p>测试文字 ABC</p></content>
|
|
1467
|
+
</shape>
|
|
1468
|
+
<line id="strike" startX="80" startY="245" endX="560" endY="245">
|
|
1469
|
+
<border color="rgb(255, 0, 0)" width="4"/>
|
|
1470
|
+
</line>
|
|
1471
|
+
</data>
|
|
1472
|
+
</slide>
|
|
1473
|
+
"""
|
|
1474
|
+
)
|
|
1475
|
+
crossing = [
|
|
1476
|
+
issue for issue in result["slides"][0]["errors"] if set(issue["elements"]) == {"strike", "title"}
|
|
1477
|
+
]
|
|
1478
|
+
self.assertEqual(len(crossing), 1)
|
|
1479
|
+
self.assertEqual(crossing[0]["code"], "bbox_overlap")
|
|
1480
|
+
|
|
1481
|
+
def test_lint_xml_reports_vertical_line_crossing_multiline_text(self) -> None:
|
|
1482
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1483
|
+
"""
|
|
1484
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1485
|
+
<data>
|
|
1486
|
+
<shape id="col" type="text" topLeftX="700" topLeftY="180" width="240" height="180">
|
|
1487
|
+
<content fontSize="20"><p>第一行文字内容</p><p>第二行文字内容</p><p>第三行文字内容</p></content>
|
|
1488
|
+
</shape>
|
|
1489
|
+
<line id="vbar" startX="740" startY="170" endX="740" endY="360">
|
|
1490
|
+
<border color="rgb(0, 0, 255)" width="3"/>
|
|
1491
|
+
</line>
|
|
1492
|
+
</data>
|
|
1493
|
+
</slide>
|
|
1494
|
+
"""
|
|
1495
|
+
)
|
|
1496
|
+
crossing = [
|
|
1497
|
+
issue for issue in result["slides"][0]["errors"] if set(issue["elements"]) == {"vbar", "col"}
|
|
1498
|
+
]
|
|
1499
|
+
self.assertEqual(len(crossing), 1)
|
|
1500
|
+
|
|
1501
|
+
def test_lint_xml_reports_diagonal_line_crossing_text_block(self) -> None:
|
|
1502
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1503
|
+
"""
|
|
1504
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1505
|
+
<data>
|
|
1506
|
+
<shape id="para" type="text" topLeftX="80" topLeftY="400" width="420" height="140">
|
|
1507
|
+
<content fontSize="18"><p>这是一段测试文字用于验证线条穿过</p></content>
|
|
1508
|
+
</shape>
|
|
1509
|
+
<line id="diag" startX="80" startY="410" endX="500" endY="530">
|
|
1510
|
+
<border color="rgb(255, 0, 0)" width="3"/>
|
|
1511
|
+
</line>
|
|
1512
|
+
</data>
|
|
1513
|
+
</slide>
|
|
1514
|
+
"""
|
|
1515
|
+
)
|
|
1516
|
+
crossing = [
|
|
1517
|
+
issue for issue in result["slides"][0]["errors"] if set(issue["elements"]) == {"diag", "para"}
|
|
1518
|
+
]
|
|
1519
|
+
self.assertEqual(len(crossing), 1)
|
|
1520
|
+
|
|
1521
|
+
def test_lint_xml_ignores_diagonal_line_whose_bbox_but_not_segment_crosses_text(self) -> None:
|
|
1522
|
+
# The diagonal's axis-aligned bounding box overlaps the text, but the segment itself passes
|
|
1523
|
+
# through empty space in the opposite corner -- a naive bbox test would false-positive here.
|
|
1524
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1525
|
+
"""
|
|
1526
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1527
|
+
<data>
|
|
1528
|
+
<shape id="corner-text" type="text" topLeftX="80" topLeftY="80" width="120" height="40">
|
|
1529
|
+
<content fontSize="18"><p>corner</p></content>
|
|
1530
|
+
</shape>
|
|
1531
|
+
<line id="far-diag" startX="700" startY="80" endX="90" endY="500">
|
|
1532
|
+
<border color="rgb(255, 0, 0)" width="3"/>
|
|
1533
|
+
</line>
|
|
1534
|
+
</data>
|
|
1535
|
+
</slide>
|
|
1536
|
+
"""
|
|
1537
|
+
)
|
|
1538
|
+
crossing = [
|
|
1539
|
+
issue for issue in result["slides"][0]["errors"] if set(issue["elements"]) == {"far-diag", "corner-text"}
|
|
1540
|
+
]
|
|
1541
|
+
self.assertEqual(crossing, [])
|
|
1542
|
+
|
|
1543
|
+
def test_lint_xml_ignores_line_touching_text_frame_but_not_glyphs(self) -> None:
|
|
1544
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1545
|
+
"""
|
|
1546
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1547
|
+
<data>
|
|
1548
|
+
<shape id="lbl" type="text" topLeftX="80" topLeftY="80" width="300" height="200">
|
|
1549
|
+
<content fontSize="18" verticalAlign="top"><p>短标签</p></content>
|
|
1550
|
+
</shape>
|
|
1551
|
+
<line id="below" startX="80" startY="270" endX="380" endY="270">
|
|
1552
|
+
<border color="rgb(255, 0, 0)" width="2"/>
|
|
1553
|
+
</line>
|
|
1554
|
+
</data>
|
|
1555
|
+
</slide>
|
|
1556
|
+
"""
|
|
1557
|
+
)
|
|
1558
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1559
|
+
|
|
1560
|
+
def test_lint_xml_ignores_invisible_line_crossing_text(self) -> None:
|
|
1561
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1562
|
+
"""
|
|
1563
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1564
|
+
<data>
|
|
1565
|
+
<shape id="title" type="text" topLeftX="80" topLeftY="200" width="500" height="90">
|
|
1566
|
+
<content fontSize="60"><p>测试文字 ABC</p></content>
|
|
1567
|
+
</shape>
|
|
1568
|
+
<line id="ghost-line" startX="80" startY="245" endX="560" endY="245">
|
|
1569
|
+
<border color="rgba(255, 0, 0, 0.03)" width="4"/>
|
|
1570
|
+
</line>
|
|
1571
|
+
</data>
|
|
1572
|
+
</slide>
|
|
1573
|
+
"""
|
|
1574
|
+
)
|
|
1575
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1576
|
+
|
|
1577
|
+
def test_lint_xml_ignores_vertical_line_grazing_text_left_edge(self) -> None:
|
|
1578
|
+
# Verbatim from deck GpGusGCwplQyK8dFN9LczmBXnwQ slide 4: a vertical line sitting on the text
|
|
1579
|
+
# frame's left edge renders before the first glyph, so it must not be flagged.
|
|
1580
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1581
|
+
"""
|
|
1582
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1583
|
+
<data>
|
|
1584
|
+
<shape width="240" height="60" topLeftX="120" topLeftY="100" type="text" id="bmm">
|
|
1585
|
+
<content fontSize="20" fontFamily="Arial" color="rgba(31, 35, 41, 1)" lineSpacing="fixed:24">
|
|
1586
|
+
<p>Vertical edge graze</p>
|
|
1587
|
+
</content>
|
|
1588
|
+
</shape>
|
|
1589
|
+
<line id="bmX" startX="120.00000000000001" startY="90" endX="120.00000000000001" endY="150.00833275470998">
|
|
1590
|
+
<border color="rgba(0, 0, 0, 1)"/>
|
|
1591
|
+
</line>
|
|
1592
|
+
</data>
|
|
1593
|
+
</slide>
|
|
1594
|
+
"""
|
|
1595
|
+
)
|
|
1596
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1597
|
+
|
|
1598
|
+
def test_lint_xml_ignores_polyline_crossing_text(self) -> None:
|
|
1599
|
+
# Verbatim from deck GpGusGCwplQyK8dFN9LczmBXnwQ slide 6: the crossing check is scoped to
|
|
1600
|
+
# <line> only, so a <polyline> over text is not flagged.
|
|
1601
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1602
|
+
"""
|
|
1603
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1604
|
+
<data>
|
|
1605
|
+
<shape width="240" height="60" topLeftX="120" topLeftY="100" type="text" id="bmr">
|
|
1606
|
+
<content fontSize="20" fontFamily="Arial" color="rgba(31, 35, 41, 1)" lineSpacing="fixed:24">
|
|
1607
|
+
<p>Polyline target</p>
|
|
1608
|
+
</content>
|
|
1609
|
+
</shape>
|
|
1610
|
+
<polyline id="bmH" width="270" height="55" topLeftX="110" topLeftY="95">
|
|
1611
|
+
<border color="rgba(0, 0, 0, 1)"/>
|
|
1612
|
+
</polyline>
|
|
1613
|
+
</data>
|
|
1614
|
+
</slide>
|
|
1615
|
+
"""
|
|
1616
|
+
)
|
|
1617
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1618
|
+
|
|
1619
|
+
def test_lint_xml_ignores_line_below_visual_glyph_height(self) -> None:
|
|
1620
|
+
# Verbatim from deck GpGusGCwplQyK8dFN9LczmBXnwQ slide 7: the shape frame is 80px tall but the
|
|
1621
|
+
# single 20px line of glyphs occupies only its top; a line at the frame's lower region grazes
|
|
1622
|
+
# under the visual glyph box (underline look) and must not be flagged.
|
|
1623
|
+
result = xml_text_overlap_lint.lint_xml(
|
|
1624
|
+
"""
|
|
1625
|
+
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
1626
|
+
<data>
|
|
1627
|
+
<shape width="240" height="80" topLeftX="120" topLeftY="100" type="text" id="bmB">
|
|
1628
|
+
<content fontSize="20" fontFamily="Arial" color="rgba(31, 35, 41, 1)" lineSpacing="fixed:24">
|
|
1629
|
+
<p>Visual height target</p>
|
|
1630
|
+
</content>
|
|
1631
|
+
</shape>
|
|
1632
|
+
<line id="bmQ" startX="110" startY="150" endX="380.00185184550116" endY="150">
|
|
1633
|
+
<border color="rgba(0, 0, 0, 1)"/>
|
|
1634
|
+
</line>
|
|
1635
|
+
</data>
|
|
1636
|
+
</slide>
|
|
1637
|
+
"""
|
|
1638
|
+
)
|
|
1639
|
+
self.assertEqual(result["summary"]["error_count"], 0)
|
|
903
1640
|
|
|
904
1641
|
def test_lint_xml_uses_rotated_text_and_chart_bounds_for_canvas_validation(self) -> None:
|
|
905
1642
|
result = xml_text_overlap_lint.lint_xml(
|
|
@@ -922,13 +1659,13 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
922
1659
|
self.assertEqual(issues_by_element["rotated-chart"]["code"], "chart_out_of_canvas")
|
|
923
1660
|
self.assertAlmostEqual(issues_by_element["rotated-chart"]["overflow"]["right"], 20.710678, places=5)
|
|
924
1661
|
|
|
925
|
-
def
|
|
1662
|
+
def test_lint_xml_uses_declared_bounds_for_rect_and_ignores_images(self) -> None:
|
|
926
1663
|
result = xml_text_overlap_lint.lint_xml(
|
|
927
1664
|
"""
|
|
928
1665
|
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
|
929
1666
|
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
|
930
1667
|
<data>
|
|
931
|
-
<shape id="rotated-rect" type="rect" topLeftX="
|
|
1668
|
+
<shape id="rotated-rect" type="rect" topLeftX="900" topLeftY="0" width="100" height="100" rotation="45"/>
|
|
932
1669
|
<img id="rotated-image" topLeftX="860" topLeftY="200" width="100" height="100" rotation="45"/>
|
|
933
1670
|
</data>
|
|
934
1671
|
</slide>
|
|
@@ -936,12 +1673,54 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
936
1673
|
"""
|
|
937
1674
|
)
|
|
938
1675
|
issues_by_element = {issue["elements"][0]: issue for issue in result["slides"][0]["issues"]}
|
|
939
|
-
self.assertEqual(result["summary"]["error_count"],
|
|
1676
|
+
self.assertEqual(result["summary"]["error_count"], 1)
|
|
940
1677
|
self.assertEqual(issues_by_element["rotated-rect"]["code"], "shape_out_of_canvas")
|
|
941
|
-
self.
|
|
942
|
-
self.
|
|
943
|
-
|
|
944
|
-
|
|
1678
|
+
self.assertEqual(issues_by_element["rotated-rect"]["overflow"], {"left": 0, "top": 0, "right": 40, "bottom": 0})
|
|
1679
|
+
self.assertNotIn("rotated-image", issues_by_element)
|
|
1680
|
+
|
|
1681
|
+
def test_detect_elements_out_of_canvas_limits_detection_to_whitelist(self) -> None:
|
|
1682
|
+
issues = xml_text_overlap_lint.detect_elements_out_of_canvas(
|
|
1683
|
+
[
|
|
1684
|
+
{"id": "table", "kind": "table", "x": 95, "y": 0, "width": 10, "height": 10, "rotation": 45},
|
|
1685
|
+
{"id": "chart", "kind": "chart", "x": 95, "y": 0, "width": 10, "height": 10, "rotation": 0},
|
|
1686
|
+
{
|
|
1687
|
+
"id": "text",
|
|
1688
|
+
"kind": "shape",
|
|
1689
|
+
"type": "text",
|
|
1690
|
+
"x": 95,
|
|
1691
|
+
"y": 0,
|
|
1692
|
+
"width": 10,
|
|
1693
|
+
"height": 10,
|
|
1694
|
+
"rotation": 0,
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
"id": "rect",
|
|
1698
|
+
"kind": "shape",
|
|
1699
|
+
"type": "rect",
|
|
1700
|
+
"x": 95,
|
|
1701
|
+
"y": 0,
|
|
1702
|
+
"width": 10,
|
|
1703
|
+
"height": 10,
|
|
1704
|
+
"rotation": 45,
|
|
1705
|
+
},
|
|
1706
|
+
{"id": "image", "kind": "img", "x": 95, "y": 0, "width": 10, "height": 10, "rotation": 0},
|
|
1707
|
+
{
|
|
1708
|
+
"id": "ellipse",
|
|
1709
|
+
"kind": "shape",
|
|
1710
|
+
"type": "ellipse",
|
|
1711
|
+
"x": 95,
|
|
1712
|
+
"y": 0,
|
|
1713
|
+
"width": 10,
|
|
1714
|
+
"height": 10,
|
|
1715
|
+
"rotation": 0,
|
|
1716
|
+
},
|
|
1717
|
+
],
|
|
1718
|
+
100,
|
|
1719
|
+
100,
|
|
1720
|
+
)
|
|
1721
|
+
|
|
1722
|
+
self.assertEqual([issue["elements"] for issue in issues], [["table"], ["chart"], ["text"], ["rect"]])
|
|
1723
|
+
self.assertEqual(issues[-1]["bbox"], {"x": 95, "y": 0, "width": 10, "height": 10})
|
|
945
1724
|
|
|
946
1725
|
def test_lint_xml_treats_non_finite_rotations_as_zero(self) -> None:
|
|
947
1726
|
result = xml_text_overlap_lint.lint_xml(
|
|
@@ -1107,8 +1886,9 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
1107
1886
|
)
|
|
1108
1887
|
issues_by_dimension = {issue["dimension"]: issue for issue in result["slides"][0]["issues"]}
|
|
1109
1888
|
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1110
|
-
self.assertEqual(result["summary"]["warning_count"],
|
|
1111
|
-
self.assertEqual(
|
|
1889
|
+
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
1890
|
+
self.assertEqual(result["summary"]["info_count"], 2)
|
|
1891
|
+
self.assertEqual(issues_by_dimension["width"]["level"], "info")
|
|
1112
1892
|
self.assertEqual(issues_by_dimension["width"]["code"], "table_resolved_size_mismatch")
|
|
1113
1893
|
self.assertEqual(issues_by_dimension["width"]["resolved_sizes"], [100, 100, 50])
|
|
1114
1894
|
self.assertEqual(issues_by_dimension["width"]["resolved_size"], 250)
|
|
@@ -1201,7 +1981,7 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
1201
1981
|
}
|
|
1202
1982
|
script_path = Path(xml_text_overlap_lint.__file__).resolve()
|
|
1203
1983
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
1204
|
-
for name, (table_xml,
|
|
1984
|
+
for name, (table_xml, expected_info_count) in cases.items():
|
|
1205
1985
|
with self.subTest(case=name):
|
|
1206
1986
|
input_path = Path(temp_dir) / f"{name}.xml"
|
|
1207
1987
|
input_path.write_text(
|
|
@@ -1221,9 +2001,10 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
1221
2001
|
result = json.loads(completed.stdout)
|
|
1222
2002
|
self.assertEqual(completed.returncode, 0, completed.stderr)
|
|
1223
2003
|
self.assertEqual(result["summary"]["error_count"], 0)
|
|
1224
|
-
self.assertEqual(result["summary"]["warning_count"],
|
|
2004
|
+
self.assertEqual(result["summary"]["warning_count"], 0)
|
|
2005
|
+
self.assertEqual(result["summary"]["info_count"], expected_info_count)
|
|
1225
2006
|
self.assertTrue(
|
|
1226
|
-
all(issue["level"] == "
|
|
2007
|
+
all(issue["level"] == "info" for issue in result["slides"][0]["issues"]),
|
|
1227
2008
|
result["slides"][0]["issues"],
|
|
1228
2009
|
)
|
|
1229
2010
|
|
|
@@ -1268,8 +2049,9 @@ class XmlTextOverlapLintGeometryTest(unittest.TestCase):
|
|
|
1268
2049
|
"""
|
|
1269
2050
|
)
|
|
1270
2051
|
issue = next(issue for issue in result["slides"][0]["issues"] if issue["code"] == "image_may_cover_vertical_text")
|
|
1271
|
-
self.assertEqual(issue["level"], "
|
|
2052
|
+
self.assertEqual(issue["level"], "info")
|
|
1272
2053
|
self.assertEqual(result["summary"]["error_count"], 0)
|
|
2054
|
+
self.assertEqual(result["summary"]["info_count"], 1)
|
|
1273
2055
|
|
|
1274
2056
|
|
|
1275
2057
|
class XmlTextOverlapLintDensityTest(unittest.TestCase):
|
|
@@ -1357,7 +2139,7 @@ class XmlTextOverlapLintDensityTest(unittest.TestCase):
|
|
|
1357
2139
|
"id": "sparse_container_content",
|
|
1358
2140
|
})
|
|
1359
2141
|
self.assertEqual(issue["measurement"]["container_area"], 151700)
|
|
1360
|
-
self.assertEqual(issue["measurement"]["content_coverage_ratio"], 0.
|
|
2142
|
+
self.assertEqual(issue["measurement"]["content_coverage_ratio"], 0.03)
|
|
1361
2143
|
self.assertEqual(issue["elements"], ["trend-card", "trend-title", "trend-copy"])
|
|
1362
2144
|
self.assertEqual(issue["element_ids"], ["trend-card", "trend-title", "trend-copy"])
|
|
1363
2145
|
self.assertEqual(
|
|
@@ -1842,9 +2624,9 @@ class XmlTextOverlapLintDensityTest(unittest.TestCase):
|
|
|
1842
2624
|
# Must match the visual bbox that should_flag_overlap actually decided with (fontSize=14
|
|
1843
2625
|
# from extract_elements), not the fontSize=96 max-descendant value that
|
|
1844
2626
|
# extract_density_elements computes for the same "left" element id.
|
|
1845
|
-
self.assertEqual(issue["measurement"]["intersection_width"],
|
|
2627
|
+
self.assertEqual(issue["measurement"]["intersection_width"], 109.2)
|
|
1846
2628
|
self.assertEqual(issue["measurement"]["intersection_height"], 6.8)
|
|
1847
|
-
self.assertEqual(issue["measurement"]["intersection_area"],
|
|
2629
|
+
self.assertEqual(issue["measurement"]["intersection_area"], 742.56)
|
|
1848
2630
|
|
|
1849
2631
|
def test_has_similar_short_card_peer_excludes_the_element_itself(self) -> None:
|
|
1850
2632
|
card_a = {"kind": "shape", "type": "rect", "x": 0, "y": 0, "width": 300, "height": 100}
|