From 6840e8d92a6570cf65ddaef5f585de74d8c2e49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Sat, 26 Feb 2022 21:10:07 -0800 Subject: [PATCH] Quick hack with sass-embedded --- lib/sprockets/sass_cache_store.rb | 30 -- lib/sprockets/sass_compressor.rb | 21 +- lib/sprockets/sass_functions.rb | 3 - lib/sprockets/sass_importer.rb | 3 - lib/sprockets/sass_processor.rb | 102 +++--- sprockets.gemspec | 2 +- test/fixtures/octicons/octicons.scss | 2 +- test/shared_sass_embedded_tests.rb | 309 +++++++++++++++++++ test/shared_sass_tests.rb | 2 +- test/test_erb_processor.rb | 2 +- test/{test_sass.rb => test_sass_embedded.rb} | 51 +-- 11 files changed, 408 insertions(+), 119 deletions(-) delete mode 100644 lib/sprockets/sass_cache_store.rb delete mode 100644 lib/sprockets/sass_functions.rb delete mode 100644 lib/sprockets/sass_importer.rb create mode 100644 test/shared_sass_embedded_tests.rb rename test/{test_sass.rb => test_sass_embedded.rb} (66%) diff --git a/lib/sprockets/sass_cache_store.rb b/lib/sprockets/sass_cache_store.rb deleted file mode 100644 index 088c0d236..000000000 --- a/lib/sprockets/sass_cache_store.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true -require 'sass' - -module Sprockets - class SassProcessor - # Internal: Cache wrapper for Sprockets cache adapter. - class CacheStore < ::Sass::CacheStores::Base - VERSION = '1' - - def initialize(cache, version) - @cache, @version = cache, "#{VERSION}/#{version}" - end - - def _store(key, version, sha, contents) - @cache.set("#{@version}/#{version}/#{key}/#{sha}", contents, true) - end - - def _retrieve(key, version, sha) - @cache.get("#{@version}/#{version}/#{key}/#{sha}", true) - end - - def path_to(key) - key - end - end - end - - # Deprecated: Use Sprockets::SassProcessor::CacheStore instead. - SassCacheStore = SassProcessor::CacheStore -end diff --git a/lib/sprockets/sass_compressor.rb b/lib/sprockets/sass_compressor.rb index 5a1901e24..e33f3ff1c 100644 --- a/lib/sprockets/sass_compressor.rb +++ b/lib/sprockets/sass_compressor.rb @@ -17,7 +17,7 @@ module Sprockets # Sprockets::SassCompressor.new({ ... }) # class SassCompressor - VERSION = '1' + VERSION = '2' # Public: Return singleton instance with default options. # @@ -38,23 +38,22 @@ def self.cache_key def initialize(options = {}) @options = { - syntax: :scss, - cache: false, - read_cache: false, - style: :compressed + syntax: :css, + style: :compressed, + source_map: true }.merge(options).freeze - @cache_key = "#{self.class.name}:#{Autoload::Sass::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze + @cache_key = "#{self.class.name}:#{Autoload::Sass::Embedded::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze end def call(input) - css, map = Autoload::Sass::Engine.new( + result = Autoload::Sass.compile_string( input[:data], - @options.merge(filename: input[:filename]) - ).render_with_sourcemap('') + **@options.merge(url: URIUtils.build_asset_uri(input[:filename])) + ) - css = css.sub("/*# sourceMappingURL= */\n", '') + css = result.css - map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input) + map = SourceMapUtils.format_source_map(JSON.parse(result.source_map), input) map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map) { data: css, map: map } diff --git a/lib/sprockets/sass_functions.rb b/lib/sprockets/sass_functions.rb deleted file mode 100644 index 9c358c8e3..000000000 --- a/lib/sprockets/sass_functions.rb +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true -# Deprecated: Require sprockets/sass_processor instead -require 'sprockets/sass_processor' diff --git a/lib/sprockets/sass_importer.rb b/lib/sprockets/sass_importer.rb deleted file mode 100644 index 9c358c8e3..000000000 --- a/lib/sprockets/sass_importer.rb +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true -# Deprecated: Require sprockets/sass_processor instead -require 'sprockets/sass_processor' diff --git a/lib/sprockets/sass_processor.rb b/lib/sprockets/sass_processor.rb index ebdc1943d..94ebd986a 100644 --- a/lib/sprockets/sass_processor.rb +++ b/lib/sprockets/sass_processor.rb @@ -13,12 +13,30 @@ module Sprockets # https://github.com/rails/sass-rails # class SassProcessor - autoload :CacheStore, 'sprockets/sass_cache_store' + VERSION = '2' # Internal: Defines default sass syntax to use. Exposed so the ScssProcessor # may override it. def self.syntax - :sass + :indented + end + + # Public: Convert ::Sass::Script::Functions to dart-sass functions option. + # + # Returns Hash object. + def self.functions(options = {}) + functions = {} + instance = Class.new.extend(::Sass::Script::Functions) + instance.define_singleton_method(:options, ->() { options }) + ::Sass::Script::Functions.public_instance_methods.each do |symbol| + parameters = instance.method(symbol).parameters + .filter { |parameter| parameter.first == :req } + .map { |parameter| "$#{parameter.last}" } + functions["#{symbol}(#{parameters.join(', ')})"] = lambda do |args| + instance.send(symbol, *args) + end + end + functions end # Public: Return singleton instance with default options. @@ -46,8 +64,7 @@ def self.cache_key # def initialize(options = {}, &block) @cache_version = options[:cache_version] - @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::VERSION}:#{@cache_version}".freeze - @importer_class = options[:importer] || Sass::Importers::Filesystem + @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::Embedded::VERSION}:#{@cache_version}".freeze @sass_config = options[:sass_config] || {} @functions = Module.new do include Functions @@ -59,35 +76,37 @@ def initialize(options = {}, &block) def call(input) context = input[:environment].context_class.new(input) - engine_options = merge_options({ - filename: input[:filename], - syntax: self.class.syntax, - cache_store: build_cache_store(input, @cache_version), - load_paths: context.environment.paths.map { |p| @importer_class.new(p.to_s) }, - importer: @importer_class.new(Pathname.new(context.filename).to_s), - sprockets: { - context: context, - environment: input[:environment], - dependencies: context.metadata[:dependencies] - } - }) - - engine = Autoload::Sass::Engine.new(input[:data], engine_options) - - css, map = Utils.module_include(Autoload::Sass::Script::Functions, @functions) do - engine.render_with_sourcemap('') + result = Utils.module_include(::Sass::Script::Functions, @functions) do + options = merge_options({ + functions: self.class.functions({ + sprockets: { + context: context, + environment: input[:environment], + dependencies: context.metadata[:dependencies] + } + }), + syntax: self.class.syntax, + source_map: true, + load_paths: context.environment.paths, + url: URIUtils.build_asset_uri(input[:filename]) + }) + + Autoload::Sass.compile_string(input[:data], **options) end - css = css.sub("\n/*# sourceMappingURL= */\n", '') + css = result.css - map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input) + map = SourceMapUtils.format_source_map(JSON.parse(result.source_map), input) map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map) # Track all imported files - sass_dependencies = Set.new([input[:filename]]) - engine.dependencies.map do |dependency| - sass_dependencies << dependency.options[:filename] - context.metadata[:dependencies] << URIUtils.build_file_digest_uri(dependency.options[:filename]) + sass_dependencies = Set.new + result.loaded_urls.each do |url| + scheme, _host, path, _query = URIUtils.split_file_uri url + if scheme == 'file' + sass_dependencies << path + context.metadata[:dependencies] << URIUtils.build_file_digest_uri(path) + end end context.metadata.merge(data: css, sass_dependencies: sass_dependencies, map: map) @@ -95,17 +114,6 @@ def call(input) private - # Public: Build the cache store to be used by the Sass engine. - # - # input - the input hash. - # version - the cache version. - # - # Override this method if you need to use a different cache than the - # Sprockets cache. - def build_cache_store(input, version) - CacheStore.new(input[:cache], version) - end - def merge_options(options) defaults = @sass_config.dup @@ -139,14 +147,14 @@ module Functions # # Returns a Sass::Script::String. def asset_path(path, options = {}) - path = path.value + path = path.text path, _, query, fragment = URI.split(path)[5..8] path = sprockets_context.asset_path(path, options) query = "?#{query}" if query fragment = "##{fragment}" if fragment - Autoload::Sass::Script::String.new("#{path}#{query}#{fragment}", :string) + Autoload::Sass::Value::String.new("#{path}#{query}#{fragment}", quoted: true) end # Public: Generate a asset url() link. @@ -155,7 +163,7 @@ def asset_path(path, options = {}) # # Returns a Sass::Script::String. def asset_url(path, options = {}) - Autoload::Sass::Script::String.new("url(#{asset_path(path, options).value})") + Autoload::Sass::Value::String.new("url(#{asset_path(path, options).text})", quoted: false) end # Public: Generate url for image path. @@ -272,8 +280,8 @@ def stylesheet_url(path) # # Returns a Sass::Script::String. def asset_data_url(path) - url = sprockets_context.asset_data_uri(path.value) - Autoload::Sass::Script::String.new("url(" + url + ")") + url = sprockets_context.asset_data_uri(path.text) + Autoload::Sass::Value::String.new("url(" + url + ")", quoted: false) end protected @@ -308,6 +316,10 @@ def self.syntax end end - # Deprecated: Use Sprockets::SassProcessor::Functions instead. - SassFunctions = SassProcessor::Functions + module ::Sass + module Script + module Functions + end + end + end end diff --git a/sprockets.gemspec b/sprockets.gemspec index 6ef3332cc..a8f44aa29 100644 --- a/sprockets.gemspec +++ b/sprockets.gemspec @@ -30,7 +30,7 @@ Gem::Specification.new do |s| s.add_development_dependency "nokogiri", "~> 1.3" s.add_development_dependency "rack-test", "~> 0.6" s.add_development_dependency "rake", "~> 12.0" - s.add_development_dependency "sass", "~> 3.4" + s.add_development_dependency "sass-embedded", "~> 1.0" s.add_development_dependency "sassc", "~> 2.0" s.add_development_dependency "uglifier", ">= 2.3" s.add_development_dependency "yui-compressor", "~> 0.12" diff --git a/test/fixtures/octicons/octicons.scss b/test/fixtures/octicons/octicons.scss index f326ce055..7a46e2dc5 100644 --- a/test/fixtures/octicons/octicons.scss +++ b/test/fixtures/octicons/octicons.scss @@ -1,5 +1,5 @@ @font-face { - font-family: 'octicons'; + font-family: octicons; src: font-url('octicons.eot?#iefix') format('embedded-opentype'), font-url('octicons.woff2') format('woff2'), font-url('octicons.woff') format('woff'), diff --git a/test/shared_sass_embedded_tests.rb b/test/shared_sass_embedded_tests.rb new file mode 100644 index 000000000..765bb855a --- /dev/null +++ b/test/shared_sass_embedded_tests.rb @@ -0,0 +1,309 @@ +# frozen_string_literal: true +module SharedSassEmbeddedTestNoFunction + extend Sprockets::TestDefinition + + test "aren't included globally" do + assert sass_functions.instance_methods.include?(:javascript_path) + assert sass_functions.instance_methods.include?(:stylesheet_path) + + filename = fixture_path('sass/paths.scss') + options = { + functions: processor.functions, + } + + assert sass_functions.instance_methods.include?(:javascript_path) + assert sass_functions.instance_methods.include?(:stylesheet_path) + + assert_equal <<-EOS.chomp, sass.compile(filename, **options).css +div { + url: url(asset-path("foo.svg")); + url: url(image-path("foo.png")); + url: url(video-path("foo.mov")); + url: url(audio-path("foo.mp3")); + url: url(font-path("foo.woff2")); + url: url(font-path("foo.woff")); + url: url("/js/foo.js"); + url: url("/css/foo.css"); +} + EOS + end +end + +module SharedSassEmbeddedTestSprockets + extend Sprockets::TestDefinition + + test "process variables" do + assert_equal <<-EOS, render('sass/variables.sass') +.content-navigation { + border-color: #3bbfce; + color: #2ca2af; +} + +.border { + padding: 8px; + margin: 8px; + border-color: #3bbfce; +} + EOS + end + + test "process nesting" do + assert_equal <<-EOS, render('sass/nesting.scss') +table.hl { + margin: 2em 0; +} +table.hl td.ln { + text-align: right; +} + +li { + font-family: serif; + font-weight: bold; + font-size: 1.2em; +} + EOS + end + + test "@import scss partial from scss" do + assert_equal <<-EOS, render('sass/import_partial.scss') +#navbar li { + border-top-radius: 10px; + -moz-border-radius-top: 10px; + -webkit-border-top-radius: 10px; +} + +#footer { + border-top-radius: 5px; + -moz-border-radius-top: 5px; + -webkit-border-top-radius: 5px; +} + +#sidebar { + border-left-radius: 8px; + -moz-border-radius-left: 8px; + -webkit-border-left-radius: 8px; +} + EOS + end + + test "@import scss partial from sass" do + assert_equal <<-EOS, render('sass/import_partial.sass') +#navbar li { + border-top-radius: 10px; + -moz-border-radius-top: 10px; + -webkit-border-top-radius: 10px; +} + +#footer { + border-top-radius: 5px; + -moz-border-radius-top: 5px; + -webkit-border-top-radius: 5px; +} + +#sidebar { + border-left-radius: 8px; + -moz-border-radius-left: 8px; + -webkit-border-left-radius: 8px; +} + EOS + end + + test "@import sass non-partial from scss" do + assert_equal <<-EOS, render('sass/import_nonpartial.scss') +.content-navigation { + border-color: #3bbfce; + color: #2ca2af; +} + +.border { + padding: 8px; + margin: 8px; + border-color: #3bbfce; +} + EOS + end + + test "@import css file from load path" do + skip "Does not work on jruby" if RUBY_PLATFORM.include?('java') + skip "Does not work on windows with sassc" if File::ALT_SEPARATOR && self.sass == ::SassC + + assert_match(/\A\s*\z/, render('sass/import_load_path.scss')) + end + + test "process css file" do + assert_equal <<-EOS, render('sass/reset.css') +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; } + EOS + end + + test "@import relative file" do + assert_equal <<-EOS, render('sass/shared/relative.scss') +#navbar li { + border-top-radius: 10px; + -moz-border-radius-top: 10px; + -webkit-border-top-radius: 10px; +} + +#footer { + border-top-radius: 5px; + -moz-border-radius-top: 5px; + -webkit-border-top-radius: 5px; +} + +#sidebar { + border-left-radius: 8px; + -moz-border-radius-left: 8px; + -webkit-border-left-radius: 8px; +} + EOS + end + + test "@import relative nested file" do + assert_equal <<-EOS, render('sass/relative.scss') +body { + background: #666666; +} + EOS + end + + test "modify file causes it to recompile" do + filename = fixture_path('sass/test.scss') + + sandbox filename do + File.open(filename, 'w') { |f| f.write "body { background: red; };" } + assert_equal "body {\n background: red;\n}\n", render(filename) + + File.open(filename, 'w') { |f| f.write "body { background: blue; };" } + mtime = Time.now + 1 + File.utime(mtime, mtime, filename) + + assert_equal "body {\n background: blue;\n}\n", render(filename) + end + end + + test "modify partial causes it to recompile" do + filename, partial = fixture_path('sass/test.scss'), fixture_path('sass/_partial.scss') + + sandbox filename, partial do + File.open(filename, 'w') { |f| f.write "@import 'partial';" } + File.open(partial, 'w') { |f| f.write "body { background: red; };" } + assert_equal "body {\n background: red;\n}\n", render(filename) + + File.open(partial, 'w') { |f| f.write "body { background: blue; };" } + mtime = Time.now + 1 + File.utime(mtime, mtime, partial) + + assert_equal "body {\n background: blue;\n}\n", render(filename) + end + end + + test "reference @import'd variable" do + assert_equal <<-EOS, render('sass/links.scss') +a:link { + color: "red"; +} + EOS + end + + test "@import reference variable" do + assert_equal <<-EOS, render('sass/main.scss') +#header { + color: "blue"; +} + EOS + end +end + +module SharedSassEmbeddedTestCompressor + extend Sprockets::TestDefinition + + def setup + @env = Sprockets::Environment.new + @env.append_path File.expand_path("../fixtures", __FILE__) + end + + test "compress css" do + uncompressed = "p {\n margin: 0;\n padding: 0;\n}" + compressed = "p{margin:0;padding:0}" + input = { + environment: @env, + filename: File.expand_path("../fixtures/uncompressed.css", __FILE__), + load_path: File.expand_path("../fixtures", __FILE__), + data: uncompressed, + metadata: {}, + cache: Sprockets::Cache.new + } + assert_equal compressed, compressor.call(input)[:data] + end +end + +module SharedSassEmbeddedTestFunctions + extend Sprockets::TestDefinition + + test "path functions" do + assert_equal <<-EOS, render('sass/paths.scss') +div { + url: url("/foo.svg"); + url: url("/foo.png"); + url: url("/foo.mov"); + url: url("/foo.mp3"); + url: url("/foo.woff2"); + url: url("/foo.woff"); + url: url("/foo.js"); + url: url("/foo.css"); +} + EOS + end + + test "url functions" do + assert_equal <<-EOS, render('sass/urls.scss') +div { + url: url(/foo.svg); + url: url(/foo.png); + url: url(/foo.mov); + url: url(/foo.mp3); + url: url(/foo.woff2); + url: url(/foo.woff); + url: url(/foo.js); + url: url(/foo.css); +} + EOS + end + + test "url functions with query and hash parameters" do + assert_equal <<-EOS, render('octicons/octicons.scss') +@font-face { + font-family: octicons; + src: url(/octicons.eot?#iefix) format("embedded-opentype"), url(/octicons.woff2) format("woff2"), url(/octicons.woff) format("woff"), url(/octicons.ttf) format("truetype"), url(/octicons.svg#octicons) format("svg"); + font-weight: normal; + font-style: normal; +} + EOS + end + + test "path function generates links" do + asset = @env.find_asset('sass/paths.css') + assert asset + + assert_equal [ + "file://#{fixture_path_for_uri('compass/foo.css')}?type=text/css&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.js')}?type=application/javascript&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.mov')}?id=xxx", + "file://#{fixture_path_for_uri('compass/foo.mp3')}?type=audio/mpeg&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.svg')}?type=image/png&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.svg')}?type=image/svg+xml&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.woff2')}?type=application/font-woff2&id=xxx", + "file://#{fixture_path_for_uri('compass/foo.woff')}?type=application/font-woff&id=xxx" + ], asset.links.to_a.map { |uri| uri.sub(/id=\w+/, 'id=xxx') }.sort + end + + test "data-url function" do + assert_equal <<-EOS, render('sass/data_url.scss') +div { + url: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAABlBMVEUFO2sAAADPfNHpAAAACklEQVQIW2NgAAAAAgABYkBPaAAAAABJRU5ErkJggg%3D%3D); +} + EOS + end +end diff --git a/test/shared_sass_tests.rb b/test/shared_sass_tests.rb index 1cfb84138..e10a0c27c 100644 --- a/test/shared_sass_tests.rb +++ b/test/shared_sass_tests.rb @@ -259,7 +259,7 @@ module SharedSassTestFunctions test "url functions with query and hash parameters" do assert_equal <<-EOS, render('octicons/octicons.scss') @font-face { - font-family: 'octicons'; + font-family: octicons; src: url(/octicons.eot?#iefix) format("embedded-opentype"), url(/octicons.woff2) format("woff2"), url(/octicons.woff) format("woff"), url(/octicons.ttf) format("truetype"), url(/octicons.svg#octicons) format("svg"); font-weight: normal; font-style: normal; } diff --git a/test/test_erb_processor.rb b/test/test_erb_processor.rb index 986381b6e..b152bc0e1 100644 --- a/test/test_erb_processor.rb +++ b/test/test_erb_processor.rb @@ -152,7 +152,7 @@ def test_compile_js_erb_template_with_top_level_constant_access environment: environment, filename: "foo.js.erb", content_type: 'application/javascript', - data: "var sass_version = '<%= Sass::VERSION %>';", + data: "var sass_version = '<%= Sass::Embedded::VERSION %>';", metadata: {}, cache: Sprockets::Cache.new } diff --git a/test/test_sass.rb b/test/test_sass_embedded.rb similarity index 66% rename from test/test_sass.rb rename to test/test_sass_embedded.rb index 2ce937204..c0c09aab7 100644 --- a/test/test_sass.rb +++ b/test/test_sass_embedded.rb @@ -1,10 +1,20 @@ # frozen_string_literal: true require 'sprockets_test' -require 'shared_sass_tests' +require 'shared_sass_embedded_tests' -silence_warnings do - require 'sass' -end +require 'sass' + +# Silent all sass compiler warnings during tests +::Sass.module_eval { + [:compile, :compile_string].each do |symbol| + original_method = singleton_method(symbol) + silent_method = lambda do |source, **kwargs| + kwargs[:logger] = ::Sass::Logger.silent + original_method.call(source, **kwargs) + end + define_singleton_method symbol, silent_method + end +} require 'sprockets/sass_processor' require 'sprockets/sass_compressor' @@ -20,8 +30,8 @@ def sass_functions ::Sass::Script::Functions end - def sass_engine - ::Sass::Engine + def processor + Sprockets::SassProcessor end def compressor @@ -38,18 +48,18 @@ def teardown class TestNoSassFunctionSass < TestBaseSass module ::Sass::Script::Functions def javascript_path(path) - ::Sass::Script::String.new("/js/#{path.value}", :string) + ::Sass::Value::String.new("/js/#{path.text}", quoted: true) end module Compass def stylesheet_path(path) - ::Sass::Script::String.new("/css/#{path.value}", :string) + ::Sass::Value::String.new("/css/#{path.text}", quoted: true) end end include Compass end - include SharedSassTestNoFunction + include SharedSassEmbeddedTestNoFunction end class TestSprocketsSass < TestBaseSass @@ -72,18 +82,15 @@ def teardown def render(path) path = fixture_path(path) - silence_warnings do - @env.find_asset(path, accept: 'text/css').to_s - end + @env.find_asset(path, accept: 'text/css').to_s end test "raise sass error with line number" do + skip 'In dart sass this prints a warning instead of throwing error' begin - ::Sass::Util.silence_sass_warnings do - render('sass/error.sass') - end + render('sass/error.sass') flunk - rescue Sass::SyntaxError => error + rescue Sass::CompileError => error assert error.message.include?("invalid") trace = error.backtrace[0] assert trace.include?("error.sass") @@ -93,9 +100,7 @@ def render(path) test "track sass dependencies metadata" do asset = nil - silence_warnings do - asset = @env.find_asset('sass/import_partial.css') - end + asset = @env.find_asset('sass/import_partial.css') assert asset assert_equal [ fixture_path('sass/_rounded.scss'), @@ -103,11 +108,11 @@ def render(path) ], asset.metadata[:sass_dependencies].to_a.sort end - include SharedSassTestSprockets + include SharedSassEmbeddedTestSprockets end -class TestSassCompressor < TestBaseSass - include SharedSassTestCompressor +class TestSassEmbeddedCompressor < TestBaseSass + include SharedSassEmbeddedTestCompressor end class TestSassFunctions < TestSprocketsSass @@ -125,5 +130,5 @@ def asset_path(path, options = {}) end end - include SharedSassTestFunctions + include SharedSassEmbeddedTestFunctions end