Skip to content

Commit

Permalink
moar tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk committed Sep 23, 2020
1 parent f0eb1d7 commit 5a851d2
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 8 deletions.
6 changes: 6 additions & 0 deletions cli/file_fetcher.rs
Expand Up @@ -79,6 +79,12 @@ impl From<String> for TextDocument {
}
}

impl From<&str> for TextDocument {
fn from(s: &str) -> Self {
TextDocument::new(s.as_bytes().to_vec(), Option::<&str>::None)
}
}

/// Structure representing local or remote file.
///
/// In case of remote file `url` might be different than originally requested URL, if so
Expand Down
152 changes: 144 additions & 8 deletions cli/graph.rs
Expand Up @@ -33,6 +33,7 @@ use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::result;
use std::time::Instant;
use swc_ecmascript::dep_graph::DependencyKind;

type Result<V> = result::Result<V, AnyError>;
Expand Down Expand Up @@ -120,6 +121,8 @@ pub trait ModuleProvider {
) -> Result<(ModuleSpecifier, MediaType)>;
}

/// An enum which represents the parsed out values of references in source code.
#[derive(Debug, Clone, Eq, PartialEq)]
enum TypeScriptReference {
Path(String),
Types(String),
Expand Down Expand Up @@ -347,14 +350,14 @@ impl Module {
}

#[derive(Clone, Debug, PartialEq)]
pub struct Stats(Vec<(String, u64)>);
pub struct Stats(Vec<(String, u128)>);

impl<'de> Deserialize<'de> for Stats {
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let items: Vec<(String, u64)> = Deserialize::deserialize(deserializer)?;
let items: Vec<(String, u128)> = Deserialize::deserialize(deserializer)?;
Ok(Stats(items))
}
}
Expand Down Expand Up @@ -462,6 +465,7 @@ impl Graph {
&mut self,
options: TranspileOptions,
) -> Result<(Stats, Option<IgnoredCompilerOptions>)> {
let start = Instant::now();
let emit_type = EmitType::Cli;
let mut compiler_options = json!({
"checkJs": false,
Expand Down Expand Up @@ -492,6 +496,7 @@ impl Graph {
transform_jsx,
};

let mut emit_count: u128 = 0;
for (_, module) in self.modules.iter_mut() {
// if the module is a Dts file we should skip it
if module.media_type == MediaType::Dts {
Expand All @@ -514,13 +519,19 @@ impl Graph {
}
let parsed_module = module.maybe_parsed_module.clone().unwrap();
let emit = parsed_module.transpile(&emit_options)?;
emit_count += 1;
module.emits.insert(emit_type.clone(), emit);
module.is_dirty = true;
}
self.flush(&emit_type)?;

// TODO(kitsonk) - provide some useful stats
Ok((Stats(Vec::new()), maybe_ignored_options))
let stats = Stats(vec![
("Files".to_string(), self.modules.len() as u128),
("Emitted".to_string(), emit_count),
("Total time".to_string(), start.elapsed().as_millis()),
]);

Ok((stats, maybe_ignored_options))
}
}

Expand Down Expand Up @@ -712,10 +723,10 @@ mod tests {
fixtures,
..MockSpecifierHandler::default()
}));
let mut builder = GraphBuilder::new(handler, None);
let specifier =
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/mod.ts")
.expect("could not resolve module");
let mut builder = GraphBuilder::new(handler, None);
builder
.insert(&specifier)
.await
Expand All @@ -732,25 +743,81 @@ mod tests {
assert_eq!(actual, expected);
}

#[tokio::test]
async fn test_graph_builder_import_map() {
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/module_graph");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
let import_map = ImportMap::from_json(
"https://deno.land/x/import_map.ts",
r#"{
"imports": {
"jquery": "./jquery.js",
"lodash": "https://unpkg.com/lodash/index.js"
}
}"#,
)
.expect("could not load import map");
let mut builder = GraphBuilder::new(handler, Some(import_map));
let specifier =
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/import_map.ts")
.expect("could not resolve module");
builder
.insert(&specifier)
.await
.expect("module not inserted");
let graph = builder.get_graph();
let actual_jquery = graph
.resolve("jquery", &specifier)
.expect("module to resolve");
let expected_jquery = (
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/jquery.js")
.expect("unable to resolve"),
MediaType::JavaScript,
);
assert_eq!(actual_jquery, expected_jquery);
let actual_lodash = graph
.resolve("lodash", &specifier)
.expect("module to resolve");
let expected_lodash = (
ModuleSpecifier::resolve_url_or_path("https://unpkg.com/lodash/index.js")
.expect("unable to resolve"),
MediaType::JavaScript,
);
assert_eq!(actual_lodash, expected_lodash);
}

#[tokio::test]
async fn test_graph_transpile() {
// This is a complex scenario of transpiling, where we have TypeScript
// importing a JavaScript file (with type definitions) which imports
// TypeScript, JavaScript, and JavaScript with type definitions.
// For scenarios where we transpile, we only want the TypeScript files
// to be actually emitted.
//
// This also exercises "@deno-types" and type references.
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/module_graph");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
let mut builder = GraphBuilder::new(handler.clone(), None);
let specifier =
ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts")
.expect("could not resolve module");
let mut builder = GraphBuilder::new(handler.clone(), None);
builder
.insert(&specifier)
.await
.expect("module not inserted");
let mut graph = builder.get_graph();
let actual = graph.transpile(TranspileOptions::default()).unwrap();
assert_eq!(actual, (Stats(Vec::new()), None));
let (stats, maybe_ignored_options) =
graph.transpile(TranspileOptions::default()).unwrap();
assert_eq!(stats.0.len(), 3);
assert_eq!(maybe_ignored_options, None);
let h = handler.borrow();
assert_eq!(h.cache_calls.len(), 2);
assert_eq!(h.cache_calls[0].1, EmitType::Cli);
Expand All @@ -768,5 +835,74 @@ mod tests {
.contains("# sourceMappingURL=data:application/json;base64,"));
assert_eq!(h.cache_calls[0].3, None);
assert_eq!(h.deps_calls.len(), 7);
assert_eq!(
h.deps_calls[0].0,
ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts").unwrap()
);
assert_eq!(h.deps_calls[0].1.len(), 1);
assert_eq!(
h.deps_calls[1].0,
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/lib/mod.js")
.unwrap()
);
assert_eq!(h.deps_calls[1].1.len(), 3);
assert_eq!(
h.deps_calls[2].0,
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/lib/mod.d.ts")
.unwrap()
);
assert_eq!(h.deps_calls[2].1.len(), 3, "should have 3 dependencies");
// sometimes the calls are not deterministic, and so checking the contents
// can cause some failures
assert_eq!(h.deps_calls[3].1.len(), 0, "should have no dependencies");
assert_eq!(h.deps_calls[4].1.len(), 0, "should have no dependencies");
assert_eq!(h.deps_calls[5].1.len(), 0, "should have no dependencies");
assert_eq!(h.deps_calls[6].1.len(), 0, "should have no dependencies");
}

#[tokio::test]
async fn test_graph_transpile_user_config() {
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/module_graph");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
let mut builder = GraphBuilder::new(handler.clone(), None);
let specifier =
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/transpile.tsx")
.expect("could not resolve module");
builder
.insert(&specifier)
.await
.expect("module not inserted");
let mut graph = builder.get_graph();
let config = r#"{
"compilerOptions": {
"target": "es5",
"jsx": "preserve"
}
}"#;
let (_, maybe_ignored_options) = graph
.transpile(TranspileOptions {
debug: false,
maybe_config: Some(config.to_string()),
})
.unwrap();
assert_eq!(
maybe_ignored_options,
Some(IgnoredCompilerOptions(vec!["target".to_string()])),
"the 'target' options should have been ignored"
);
let h = handler.borrow();
assert_eq!(h.cache_calls.len(), 1, "only one file should be emitted");
assert!(
h.cache_calls[0]
.2
.to_string()
.unwrap()
.contains("<div>Hello world!</div>"),
"jsx should have been preserved"
);
}
}
23 changes: 23 additions & 0 deletions cli/specifier_handler.rs
Expand Up @@ -559,4 +559,27 @@ pub mod tests {
);
assert_eq!(cached_module.specifier, specifier);
}

#[tokio::test]
async fn test_fetch_handler_set_cache() {
let _http_server_guard = test_util::http_server();
let (_, mut file_fetcher) = setup();
let specifier = ModuleSpecifier::resolve_url_or_path(
"http://localhost:4545/cli/tests/subdir/mod2.ts",
)
.unwrap();
let cached_module: CachedModule =
file_fetcher.fetch(specifier.clone()).await.unwrap();
assert_eq!(cached_module.emits.len(), 0);
let code = TextDocument::from("some code");
file_fetcher
.set_cache(&specifier, &EmitType::Cli, code, None)
.expect("could not set cache");
let cached_module: CachedModule =
file_fetcher.fetch(specifier.clone()).await.unwrap();
assert_eq!(cached_module.emits.len(), 1);
let actual_emit = cached_module.emits.get(&EmitType::Cli).unwrap();
assert_eq!(actual_emit.0.to_str().unwrap(), "some code");
assert_eq!(actual_emit.1, None);
}
}
4 changes: 4 additions & 0 deletions cli/tests/module_graph/https_deno.land-x-import_map.ts
@@ -0,0 +1,4 @@
import * as $ from "jquery";
import * as _ from "lodash";

console.log($, _);
3 changes: 3 additions & 0 deletions cli/tests/module_graph/https_deno.land-x-jquery.js
@@ -0,0 +1,3 @@
const $ = {};

export default $;
5 changes: 5 additions & 0 deletions cli/tests/module_graph/https_deno.land-x-transpile.tsx
@@ -0,0 +1,5 @@
export default class A {
render() {
return (<div>Hello world!</div>);
}
}
3 changes: 3 additions & 0 deletions cli/tests/module_graph/https_unpkg.com-lodash-index.js
@@ -0,0 +1,3 @@
const _ = {};

export default _;

0 comments on commit 5a851d2

Please sign in to comment.