ci: add basic test pipeline for shader builders
This commit is contained in:
26
tests/python_build/conftest.py
Normal file
26
tests/python_build/conftest.py
Normal file
@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
ROOT = CWD.parent.parent
|
||||
# append directory with build files to sys.path to import them
|
||||
sys.path.append(str(ROOT))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shader_files(request):
|
||||
shader_path = request.param
|
||||
|
||||
res = {
|
||||
"path_input": str(CWD / "fixtures" / f"{shader_path}.glsl"),
|
||||
"path_output": str(CWD / "fixtures" / f"{shader_path}.glsl.gen.h"),
|
||||
"path_expected_full": str(CWD / "fixtures" / f"{shader_path}_expected_full.glsl"),
|
||||
"path_expected_parts": str(CWD / "fixtures" / f"{shader_path}_expected_parts.json"),
|
||||
}
|
||||
yield res
|
||||
|
||||
if not os.getenv("PYTEST_KEEP_GENERATED_FILES"):
|
||||
os.remove(res["path_output"])
|
||||
1
tests/python_build/fixtures/gles3/_included.glsl
Normal file
1
tests/python_build/fixtures/gles3/_included.glsl
Normal file
@ -0,0 +1 @@
|
||||
#define M_PI 3.14159265359
|
||||
34
tests/python_build/fixtures/gles3/vertex_fragment.glsl
Normal file
34
tests/python_build/fixtures/gles3/vertex_fragment.glsl
Normal file
@ -0,0 +1,34 @@
|
||||
#include "_included.glsl"
|
||||
|
||||
#[modes]
|
||||
|
||||
mode_ninepatch = #define USE_NINEPATCH
|
||||
|
||||
#[specializations]
|
||||
|
||||
DISABLE_LIGHTING = false
|
||||
|
||||
#[vertex]
|
||||
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
layout(location = 0) in highp vec3 vertex;
|
||||
|
||||
out highp vec4 position_interp;
|
||||
|
||||
void main() {
|
||||
position_interp = vec4(vertex.x,1,0,1);
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
in highp vec4 position_interp;
|
||||
|
||||
void main() {
|
||||
highp float depth = ((position_interp.z / position_interp.w) + 1.0);
|
||||
frag_color = vec4(depth);
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
|
||||
#ifndef VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3
|
||||
#define VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3
|
||||
|
||||
|
||||
#include "drivers/gles3/shader_gles3.h"
|
||||
|
||||
|
||||
class VertexFragmentShaderGLES3 : public ShaderGLES3 {
|
||||
|
||||
public:
|
||||
|
||||
enum ShaderVariant {
|
||||
MODE_NINEPATCH,
|
||||
};
|
||||
|
||||
enum Specializations {
|
||||
DISABLE_LIGHTING=1,
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant,uint64_t p_specialization=0) { _version_bind_shader(p_version,p_variant,p_specialization); }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void _init() override {
|
||||
|
||||
static const char **_uniform_strings=nullptr;
|
||||
static const char* _variant_defines[]={
|
||||
"#define USE_NINEPATCH",
|
||||
};
|
||||
|
||||
static TexUnitPair *_texunit_pairs=nullptr;
|
||||
static UBOPair *_ubo_pairs=nullptr;
|
||||
static Specialization _spec_pairs[]={
|
||||
{"DISABLE_LIGHTING",false},
|
||||
};
|
||||
|
||||
static const char _vertex_code[]={
|
||||
10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,104,105,103,104,112,32,118,101,99,51,32,118,101,114,116,101,120,59,10,10,111,117,116,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,32,61,32,118,101,99,52,40,118,101,114,116,101,120,46,120,44,49,44,48,44,49,41,59,10,125,10,10, 0};
|
||||
|
||||
static const char _fragment_code[]={
|
||||
10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,105,110,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,104,105,103,104,112,32,102,108,111,97,116,32,100,101,112,116,104,32,61,32,40,40,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,122,32,47,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,119,41,32,43,32,49,46,48,41,59,10,9,102,114,97,103,95,99,111,108,111,114,32,61,32,118,101,99,52,40,100,101,112,116,104,41,59,10,125,10, 0};
|
||||
|
||||
_setup(_vertex_code,_fragment_code,"VertexFragmentShaderGLES3",0,_uniform_strings,0,_ubo_pairs,0,_texunit_pairs,1,_spec_pairs,1,_variant_defines);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
{
|
||||
"vertex_lines": [
|
||||
"",
|
||||
"precision highp float;",
|
||||
"precision highp int;",
|
||||
"",
|
||||
"layout(location = 0) in highp vec3 vertex;",
|
||||
"",
|
||||
"out highp vec4 position_interp;",
|
||||
"",
|
||||
"void main() {",
|
||||
"\tposition_interp = vec4(vertex.x,1,0,1);",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"fragment_lines": [
|
||||
"",
|
||||
"precision highp float;",
|
||||
"precision highp int;",
|
||||
"",
|
||||
"in highp vec4 position_interp;",
|
||||
"",
|
||||
"void main() {",
|
||||
"\thighp float depth = ((position_interp.z / position_interp.w) + 1.0);",
|
||||
"\tfrag_color = vec4(depth);",
|
||||
"}"
|
||||
],
|
||||
"uniforms": [],
|
||||
"fbos": [],
|
||||
"texunits": [],
|
||||
"texunit_names": [],
|
||||
"ubos": [],
|
||||
"ubo_names": [],
|
||||
"vertex_included_files": [],
|
||||
"fragment_included_files": [],
|
||||
"reading": "fragment",
|
||||
"line_offset": 33,
|
||||
"vertex_offset": 10,
|
||||
"fragment_offset": 23,
|
||||
"variant_defines": [
|
||||
"#define USE_NINEPATCH"
|
||||
],
|
||||
"variant_names": [
|
||||
"MODE_NINEPATCH"
|
||||
],
|
||||
"specialization_names": [
|
||||
"DISABLE_LIGHTING"
|
||||
],
|
||||
"specialization_values": [
|
||||
" false\n"
|
||||
]
|
||||
}
|
||||
1
tests/python_build/fixtures/glsl/_included.glsl
Normal file
1
tests/python_build/fixtures/glsl/_included.glsl
Normal file
@ -0,0 +1 @@
|
||||
#define M_PI 3.14159265359
|
||||
12
tests/python_build/fixtures/glsl/compute.glsl
Normal file
12
tests/python_build/fixtures/glsl/compute.glsl
Normal file
@ -0,0 +1,12 @@
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
|
||||
#include "_included.glsl"
|
||||
|
||||
void main() {
|
||||
vec3 static_light = vec3(0, 1, 0);
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
|
||||
#ifndef COMPUTE_SHADER_GLSL_RAW_H
|
||||
#define COMPUTE_SHADER_GLSL_RAW_H
|
||||
|
||||
static const char compute_shader_glsl[] = {
|
||||
35,91,99,111,109,112,117,116,101,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,118,101,99,51,32,115,116,97,116,105,99,95,108,105,103,104,116,32,61,32,118,101,99,51,40,48,44,32,49,44,32,48,41,59,10,125,10,0
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"code": "#[compute]\n\n#version 450\n\n#VERSION_DEFINES\n\n\n#define M_PI 3.14159265359\n\nvoid main() {\n\tvec3 static_light = vec3(0, 1, 0);\n}\n"
|
||||
}
|
||||
32
tests/python_build/fixtures/glsl/vertex_fragment.glsl
Normal file
32
tests/python_build/fixtures/glsl/vertex_fragment.glsl
Normal file
@ -0,0 +1,32 @@
|
||||
#[versions]
|
||||
|
||||
lines = "#define MODE_LINES";
|
||||
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
layout(location = 0) out vec3 uv_interp;
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef MODE_LINES
|
||||
uv_interp = vec3(0,0,1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "_included.glsl"
|
||||
|
||||
layout(location = 0) out vec4 dst_color;
|
||||
|
||||
void main() {
|
||||
dst_color = vec4(1,1,0,0);
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
|
||||
#ifndef VERTEX_FRAGMENT_SHADER_GLSL_RAW_H
|
||||
#define VERTEX_FRAGMENT_SHADER_GLSL_RAW_H
|
||||
|
||||
static const char vertex_fragment_shader_glsl[] = {
|
||||
35,91,118,101,114,115,105,111,110,115,93,10,10,108,105,110,101,115,32,61,32,34,35,100,101,102,105,110,101,32,77,79,68,69,95,76,73,78,69,83,34,59,10,10,35,91,118,101,114,116,101,120,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,51,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,10,35,105,102,100,101,102,32,77,79,68,69,95,76,73,78,69,83,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,51,40,48,44,48,44,49,41,59,10,35,101,110,100,105,102,10,125,10,10,35,91,102,114,97,103,109,101,110,116,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,52,32,100,115,116,95,99,111,108,111,114,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,100,115,116,95,99,111,108,111,114,32,61,32,118,101,99,52,40,49,44,49,44,48,44,48,41,59,10,125,10,0
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"code": "#[versions]\n\nlines = \"#define MODE_LINES\";\n\n#[vertex]\n\n#version 450\n\n#VERSION_DEFINES\n\nlayout(location = 0) out vec3 uv_interp;\n\nvoid main() {\n\n#ifdef MODE_LINES\n\tuv_interp = vec3(0,0,1);\n#endif\n}\n\n#[fragment]\n\n#version 450\n\n#VERSION_DEFINES\n\n#define M_PI 3.14159265359\n\nlayout(location = 0) out vec4 dst_color;\n\nvoid main() {\n\tdst_color = vec4(1,1,0,0);\n}\n"
|
||||
}
|
||||
1
tests/python_build/fixtures/rd_glsl/_included.glsl
Normal file
1
tests/python_build/fixtures/rd_glsl/_included.glsl
Normal file
@ -0,0 +1 @@
|
||||
#define M_PI 3.14159265359
|
||||
13
tests/python_build/fixtures/rd_glsl/compute.glsl
Normal file
13
tests/python_build/fixtures/rd_glsl/compute.glsl
Normal file
@ -0,0 +1,13 @@
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#define BLOCK_SIZE 8
|
||||
|
||||
#include "_included.glsl"
|
||||
|
||||
void main() {
|
||||
uint t = BLOCK_SIZE + 1;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
|
||||
#ifndef COMPUTE_GLSL_GEN_H_RD
|
||||
#define COMPUTE_GLSL_GEN_H_RD
|
||||
|
||||
#include "servers/rendering/renderer_rd/shader_rd.h"
|
||||
|
||||
class ComputeShaderRD : public ShaderRD {
|
||||
|
||||
public:
|
||||
|
||||
ComputeShaderRD() {
|
||||
|
||||
static const char _compute_code[] = {
|
||||
10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,66,76,79,67,75,95,83,73,90,69,32,56,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,105,110,116,32,116,32,61,32,66,76,79,67,75,95,83,73,90,69,32,43,32,49,59,10,125,10,0
|
||||
};
|
||||
setup(nullptr, nullptr, _compute_code, "ComputeShaderRD");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,28 @@
|
||||
{
|
||||
"vertex_lines": [],
|
||||
"fragment_lines": [],
|
||||
"compute_lines": [
|
||||
"",
|
||||
"#version 450",
|
||||
"",
|
||||
"#VERSION_DEFINES",
|
||||
"",
|
||||
"#define BLOCK_SIZE 8",
|
||||
"",
|
||||
"#define M_PI 3.14159265359",
|
||||
"",
|
||||
"void main() {",
|
||||
"\tuint t = BLOCK_SIZE + 1;",
|
||||
"}"
|
||||
],
|
||||
"vertex_included_files": [],
|
||||
"fragment_included_files": [],
|
||||
"compute_included_files": [
|
||||
"tests/python_build/fixtures/rd_glsl/_included.glsl"
|
||||
],
|
||||
"reading": "compute",
|
||||
"line_offset": 13,
|
||||
"vertex_offset": 0,
|
||||
"fragment_offset": 0,
|
||||
"compute_offset": 1
|
||||
}
|
||||
25
tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl
Normal file
25
tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl
Normal file
@ -0,0 +1,25 @@
|
||||
#[vertex]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#include "_included.glsl"
|
||||
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
|
||||
void main() {
|
||||
uv_interp = vec2(0, 1);
|
||||
}
|
||||
|
||||
#[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
#VERSION_DEFINES
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
|
||||
void main() {
|
||||
uv_interp = vec2(1, 0);
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
|
||||
#ifndef VERTEX_FRAGMENT_GLSL_GEN_H_RD
|
||||
#define VERTEX_FRAGMENT_GLSL_GEN_H_RD
|
||||
|
||||
#include "servers/rendering/renderer_rd/shader_rd.h"
|
||||
|
||||
class VertexFragmentShaderRD : public ShaderRD {
|
||||
|
||||
public:
|
||||
|
||||
VertexFragmentShaderRD() {
|
||||
|
||||
static const char _vertex_code[] = {
|
||||
10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,48,44,32,49,41,59,10,125,10,10,0
|
||||
};
|
||||
static const char _fragment_code[] = {
|
||||
10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,49,44,32,48,41,59,10,125,10,0
|
||||
};
|
||||
setup(_vertex_code, _fragment_code, nullptr, "VertexFragmentShaderRD");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,40 @@
|
||||
{
|
||||
"vertex_lines": [
|
||||
"",
|
||||
"#version 450",
|
||||
"",
|
||||
"#VERSION_DEFINES",
|
||||
"",
|
||||
"#define M_PI 3.14159265359",
|
||||
"",
|
||||
"layout(location = 0) out vec2 uv_interp;",
|
||||
"",
|
||||
"void main() {",
|
||||
"\tuv_interp = vec2(0, 1);",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"fragment_lines": [
|
||||
"",
|
||||
"#version 450",
|
||||
"",
|
||||
"#VERSION_DEFINES",
|
||||
"",
|
||||
"layout(location = 0) in vec2 uv_interp;",
|
||||
"",
|
||||
"void main() {",
|
||||
"\tuv_interp = vec2(1, 0);",
|
||||
"}"
|
||||
],
|
||||
"compute_lines": [],
|
||||
"vertex_included_files": [
|
||||
"tests/python_build/fixtures/rd_glsl/_included.glsl"
|
||||
],
|
||||
"fragment_included_files": [],
|
||||
"compute_included_files": [],
|
||||
"reading": "fragment",
|
||||
"line_offset": 25,
|
||||
"vertex_offset": 1,
|
||||
"fragment_offset": 15,
|
||||
"compute_offset": 0
|
||||
}
|
||||
31
tests/python_build/test_gles3_builder.py
Normal file
31
tests/python_build/test_gles3_builder.py
Normal file
@ -0,0 +1,31 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from gles3_builders import build_gles3_header, GLES3HeaderStruct
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["shader_files", "builder", "header_struct"],
|
||||
[
|
||||
("gles3/vertex_fragment", build_gles3_header, GLES3HeaderStruct),
|
||||
],
|
||||
indirect=["shader_files"],
|
||||
)
|
||||
def test_gles3_builder(shader_files, builder, header_struct):
|
||||
header = header_struct()
|
||||
|
||||
builder(shader_files["path_input"], "drivers/gles3/shader_gles3.h", "GLES3", header_data=header)
|
||||
|
||||
with open(shader_files["path_expected_parts"], "r") as f:
|
||||
expected_parts = json.load(f)
|
||||
assert expected_parts == header.__dict__
|
||||
|
||||
with open(shader_files["path_output"], "r") as f:
|
||||
actual_output = f.read()
|
||||
assert actual_output
|
||||
|
||||
with open(shader_files["path_expected_full"], "r") as f:
|
||||
expected_output = f.read()
|
||||
|
||||
assert actual_output == expected_output
|
||||
37
tests/python_build/test_glsl_builder.py
Normal file
37
tests/python_build/test_glsl_builder.py
Normal file
@ -0,0 +1,37 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from glsl_builders import build_raw_header, RAWHeaderStruct, build_rd_header, RDHeaderStruct
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
[
|
||||
"shader_files",
|
||||
"builder",
|
||||
"header_struct",
|
||||
],
|
||||
[
|
||||
("glsl/vertex_fragment", build_raw_header, RAWHeaderStruct),
|
||||
("glsl/compute", build_raw_header, RAWHeaderStruct),
|
||||
("rd_glsl/vertex_fragment", build_rd_header, RDHeaderStruct),
|
||||
("rd_glsl/compute", build_rd_header, RDHeaderStruct),
|
||||
],
|
||||
indirect=["shader_files"],
|
||||
)
|
||||
def test_glsl_builder(shader_files, builder, header_struct):
|
||||
header = header_struct()
|
||||
builder(shader_files["path_input"], header_data=header)
|
||||
|
||||
with open(shader_files["path_expected_parts"], "r") as f:
|
||||
expected_parts = json.load(f)
|
||||
assert expected_parts == header.__dict__
|
||||
|
||||
with open(shader_files["path_output"], "r") as f:
|
||||
actual_output = f.read()
|
||||
assert actual_output
|
||||
|
||||
with open(shader_files["path_expected_full"], "r") as f:
|
||||
expected_output = f.read()
|
||||
|
||||
assert actual_output == expected_output
|
||||
Reference in New Issue
Block a user